🧞‍♂️

個人開発してた新卒エンジニアが技術研修を受けたら、まだ学ぶべきことが山程あると気付かされた!

2024/07/30に公開

こんにちは。Genieeの新卒エンジニアの岩井です。
Genieeでは、新卒エンジニアを対象に2ヶ月間、先輩社員がbootcampという名前の技術研修を実施してくれます。
この記事では、bootcampを経験して感じたことを中心に、bootcampとは何か、実際にどういった内容を習得するかについてお話ししていきたいとおもいます。

著者について


DOOH開発所属。
SaaSやRPAが好きで、マーケティングSaaSに惹かれて入社...したものの、入社後のプロダクトの詳細な説明を聞き、「外の!大きな!ディスプレイに!動的に!?広告映像を流せる!?」と感動してDOOH(デジタル屋外広告)を志望。


学生時代は個人的興味やサークルやバイトの影響で手当たり次第にプログラムに触れていたため、以下のようなスキルセットになりました。

  • C言語...これでプログラムに入門。DxLibで弾幕ゲームや横スクロールゲームを作成。
  • Java...Cの次に触った言語。tomcatやServletで特に理解せずサーバーアプリを書いていた。
  • C#&.net&Unity...ゲーム作成・デスクトップアプリとして使用
  • Python...seleniumでサイトを自動操作するために覚えた。その後も何かと使用。卒検でも使用。
  • JavaScript...Djangoで作ったwebアプリを動的にした。
  • React...バニラJSでずっと.appendChild()し続ける苦行に耐えかねた
  • Next.js...Reactだけでルーティングする苦行に耐えかねた。(辛すぎる。二度としたくない作業)
  • Go言語...DjangoでAPIを書いていたらいつの間にか正しい型で出力できなくなってしまったのでパッケージ管理が楽な静的型付け言語に入門。
  • GAS(js)...バイト先のスプシとchatworkを連携したくて。

研修の感想

上記の通り、私は大学時代に色々と作ってきたので、自分の技術力には自信を持っていました。特に、DBは情報系学部生の中でも使っている方だと自身があり、研修が始まる前はスラスラ解けるだろうと思っていました。

しかし、実際に研修が始まると、その自信は無くなりました。つまりこうです。
ダニング=クルーガー効果
各研修で、単に「使えれば良いだろう」という認識を持っていた自分が、いかに浅い知識しか身につけていなかったかを痛感させられました。
使えていても、なぜ動いているかをもっと理解しなければ、私は何かあったときに対処できないのです。

では、この感想に至った道のりを、これからご紹介します。

研修の概要と目的

bootcampは、主に2年目の先輩エンジニアが、新卒エンジニアに行ってくれる技術研修です。合計2ヶ月あり、今年は下のように行われました。

タイトル
Unixコマンド
AI
Git
コードレビュー
仮想技術・Docker
ドキュメントライティング
DB(SQL,テーブル設計,パフォーマンスチューニング,NoSQL)
HTML&CSS
Javascript
Typescript
DevTools
コンピュータシステム
Webアプリケーションフレームワーク
LEMP
Go
テスト
React
チーム研修1(短い)
クラウド
デバッグ
Redisサーバ作成(Golang)
セキュリティ
PHP/デザインパターン
データ構造とアルゴリズム
チーム研修2(長い)

毎日非常に濃い内容になっていました。
また、この研修は全体を通して生産性の高い業務の進め方の練習という側面もありました。そのためAIの使用が許可...というよりかなり推奨されていました。私達が主に使っていたAIツールは、JAPAN AI CHATというAIチャットツールでした。

JAPAN AI CHAT

JAPAN AI CHATとは、Genieeの子会社であるJAPAN AIが開発しているAIチャットツールです。通常のChatGPTの機能に追加して、

  • 質問の形式をテンプレート化して保存
  • 入力したURLのページの内容から検索させる

などができます。
また、入力情報がAIの学習に利用されることはないため、業務中に使って良いことも利点です。
ホームページはこちら
(この記事にアスキーアートが多いのも、AIのおかげだったりします。)


さて、次のセクションから、特に印象に残った研修をご紹介します。

特に印象に残った研修

Docker研修

この研修は、この研修のレベルが尋常でないと気づいたきっかけになる研修でした。ただDockerコマンドを使えれば良いのかなと思っていたら、OverlayFSでDockerが生成するファイルと同じ構成を作ったり、namespaceやcgroupを確認したりと、明らかに「Dockerを使えればいい」レベルを超えたものでした。

namespaceのイメージ図
+-----------------------------------------------------+
| OS                                                  |
|                                                     |
|  +---------------------+  +---------------------+   |
|  | Namespace 1         |  | Namespace 2         |   |
|  |                     |  |                     |   |
|  |  +---------------+  |  |  +---------------+  |   |
|  |  | /etc          |  |  |  | /etc          |  |   |
|  |  | /proc         |  |  |  | /proc         |  |   |
|  |  | /dev          |  |  |  | /dev          |  |   |
|  |  | /sys          |  |  |  | /sys          |  |   |
|  |  | /var          |  |  |  | /var          |  |   |
|  |  +---------------+  |  |  +---------------+  |   |
|  |                     |  |                     |   |
|  +---------------------+  +---------------------+   |
|                                                     |
+-----------------------------------------------------+

業務はこのレベルの理解が必要なのかと知り、慄くとともに楽しみになりました。
ちなみにこの日の目標は、「仮想化の仕組みをざっくりわかってもらう」と書かれていました。

DB研修(パフォーマンス・チューニング)

始めは「ループ文の中でインサートを繰り返しているので、バルクインサートにしてみよう」くらいの軽い内容でした。

# FIXME [X--] Q. バルクインサートにしてみよう
for department in departments:
    cursor.execute(
        "INSERT INTO departments (id, name, code, created_at) VALUES (%(id)s, %(name)s, %(code)s, %(created_at)s)",
        {
            "id": department["id"],
            "name": department["name"],
            "code": department["code"],
            "created_at": department["created_at"],
        },
    )
# -------------------------------------------
# これを、下のように書き直す
# Answer
cursor.executemany(
    "INSERT INTO departments (id, name, code, created_at) VALUES (%(id)s, %(name)s, %(code)s, %(created_at)s)",
    [{
            "id": department["id"],
            "name": department["name"],
            "code": department["code"],
            "created_at": department["created_at"],
        } for department in departments]
)

途中から難易度が跳ね上がり、手も足も出なくなりました。後日、回答コードを配ってもらえましたが、JSON_ARRAYAGGJSON_OBJECTなど、聞いたことがない句が並んでいました。
【DB構成の例】

難しい問題の例
# FIXME [XXX] ループ内で数多くのクエリが発行されるため遅い。回数を減らしてみよう。
# Answer
# タスク管理システムでタスク情報を取得し、それに関連する担当者、フィードバック、およびリアクションの情報を集約する。
cursor.execute("""
WITH ta AS
(
    SELECT task_id, JSON_ARRAYAGG(JSON_OBJECT('employee_id', employee_id)) AS taarr
    FROM task_assignments
    GROUP BY task_id
),
tf AS
(
    SELECT task_id, JSON_ARRAYAGG(JSON_OBJECT('employee_id', employee_id, 'feedback_score', feedback_score, 'feedback_at', feedback_at)) AS tfobj
    FROM task_feedback
    GROUP BY task_id
),
tr AS
(
    SELECT task_id, JSON_ARRAYAGG(JSON_OBJECT('employee_id', employee_id, 'reaction_type', reaction_type, 'reacted_at', reacted_at)) AS trobj
    FROM task_reactions
    GROUP BY task_id
)
SELECT id, description, assigned_by, priority, related_task_id as related_task_id, created_at, taarr, tfobj, trobj
FROM tasks t
LEFT OUTER JOIN ta
ON t.id = ta.task_id
LEFT OUTER JOIN tf
ON t.id = tf.task_id
LEFT OUTER JOIN tr
ON t.id = tr.task_id
ORDER BY created_at, id
""")

AIに聞いても一発では出なかったので、もう趣味でクエリのドキュメントを読むしかこのテクニックは仕入れられなそうです。
ここで、この研修は全体的にとんでもなく高いレベルだと理解しました。

コンピュータシステム研修

「コンピュータシステム」という題名は、何をやるか分からないですが、OS関連なのかな?とは思っていました。確かに座学の時間中はOSのユーザーモードとカーネルモードの話などがありましたが、演習したのは、vethやbridgeのセッティングでした。これはつまり、docker composeが立ち上がる時にコンテナ同士やホストとネットワークをどのように繋いでいるのか理解するための演習でした。

ネットワークネームスペースとbridgeの図
+-------------------+        +-------------------+
|                   |        |                   |
|   Network         |        |   Network         |
|   Namespace       |        |   Namespace       |
|   ntns1           |        |   ntns2           |
|                   |        |                   |
|  172.17.2.10/16   |        |  172.17.2.20/16   |
|                   |        |                   |
|   +-----------+   |        |   +-----------+   |
|   | veth-ntns1|   |        |   | veth-ntns2|   |
|   +-----------+   |        |   +-----------+   |
|        |          |        |         |         |
+--------|----------+        +---------|---------+
         |                             |
         |                             |
         |                             |
  +------|-----------------------------|---------+
  | +---------------+          +---------------+ |
  | | bridge-veth-1 |          | bridge-veth-2 | |
  | +----|----------+          +--------|------+ |
  |      |                              |        |
  |    +-|------------------------------|-+      |
  |    |       Bridge (net-v-bridge)      |      |
  |    |       172.17.1.10/16             |      |
  |    +----------------------------------+      |
  +----------------------------------------------+

bootcampは、全体的にDockerへの理解を大事にしているようでした。そして講師は当たり前のように講義内容を理解していることが、つまり来年はああならなければならないことを示しており、大変プレッシャーを感じました。

データ構造とアルゴリズム

同期の競プロ勢、AtCorder水色以上がごろごろいらっしゃいます。彼らの目がキラキラしてました。競プロ勢ではない私は、合格レベルまでが精一杯でした。競プロ勢からヒントを少しもらいましたが、動的計画法が必要だったそうです。その時知ってその時作れるものではなかったです。アルゴリズムって、まだ意外とAIが役立たない領域だということが分かりました。しかし自分で調べたところで考え方だけ出て、数式すら辿り着けませんでした。
競プロerは一部、全問正解者が出ていました。
怖いのはここからで、いや、まあ私も得意分野でそんな状況になればやりますが、次の日には他の競プロerも解いてきていたんです。う~ん強い。

チーム研修2

研修期間最後の2週間は、8人のチームでWEBアプリを開発する研修です!私の役割はバックエンドのリーダーでした。
技術スタックは

  • Golang
  • Next.js(App router)
  • GCP
    を使いました。

チーム研修1(4人チーム3日間)ではリーダーをしていましたが、私の個人開発のときの開発スタイルをそのまま適用したせいで、古風な香り漂うWEB"サイト"が出来上がりました。その手法は、まずはHTMLやDOM、ルーティングを作り、UIは基礎機能ができてから後でまとめて書くというものです。そしてUIを作る時間がなくなり...THE・HTMLな見た目になってしまいました。

【Next.jsで作られていることが信じられないようなUI】
THE HTML

この仕上がりを見て怖気づいてしまい、チーム研修2ではWEBアプリのバックエンドを担当することにしました。
主に担当したのは、jwtやcsrfトークンのチェック機構や、ディレクトリ構成の設計です。チームではGo言語を使っていたため、循環参照をしないようにimportのルールは最初に決めました。チーム研修中一度も循環参照をしたい状況を起こさなかったことがちょっとした自慢です。

ルールの例
/...アプリのルート
|-pkg...どこからでも参照できるように、他の内部パッケージを参照しない
|-internal
    |-<app1>...他のinternalを参照しない
    |-<app2>

さて、私にとっては大問題のUIですが...なんとめちゃめちゃ綺麗に作られていました。また、フロントエンドチームはUI以外にも、コンポーネントの粒度に気をつけていて、途中から加入した人にも優しい設計になっていて、とても勉強になりました。
他にも、リーダーは毎日デイリースクラムのフォーマットをブラッシュアップしていたり、インフラチームはGCPでいつの間にかCI/CDを構築していたり、各々全員強かったです。

bootcampを経て感じた変化

さて、bootcampが終わり、配属発表も終わり、いよいよ業務が始まりました。
技術力・対人関係の2つの観点から、私の入社時からの変化を振り返ってみたいと思います。

技術力の向上!

技術研修の主目的である技術力は、しっかり向上しました。特に新しい言語をできるようになったことはありませんが、今まで避けてきた低レイヤー周りや、微妙に難しい概念の理解がとても深まりました。
また、これらを習得する過程で、新しい概念を習得するハードルがぐんと下がり、新しいものの習得に抵抗が無くなりました。
講義内ではGitHub CopilotやJAPAN AIなどの生成AIツールの使用も許可されていました。AIを全く使わずググるだけだと進みが遅くなり、AIに頼ってばかりだと詰めが甘くなり完成までいけない。最終的にAIとGoogle検索、公式ドキュメントを読みながらの試行錯誤のバランスを取れるようになりました。

同期をよく知れた!

bootcampでは導入研修に加えてエンジニア・プログラマーとしての交流をしたことで、各々のプログラミング経歴や得意言語・得意分野を理解することができました。実際、UIが得意な人、バックエンドばかり触っていたけど実際やってみるとなんでもできる人、導入研修中は謙遜していたが強い資格を持っていた人が居ました。同期理解と同時に、いろいろな強みのベクトルを知ったことで、視点が広がったと感じます!

配属後から振り返る、bootcampの意味

DOOHに配属されてから2週間が経ちました。研修中に学んだ技術は、実際に使うことよりも、その挙動を理解することが重要であると感じています。新卒はプロジェクトに途中から参加するため、既存のコードに書き加える作業から始まることが多いです。そのため、標準のコードが理解できなければ、作業を進めることができません。コードを読めることで、複雑なドメイン知識も効率的に吸収できると痛感しました。

研修と業務を通じて、私は「まだまだ自分には学ぶべきことがたくさんある」と強く感じました。業務で、実際に使うということは、つまり何かが起きたときに状態をすべて把握できなければいけないのです。
その調査力の向上、そして、来年の新卒エンジニアに驚かれるために、私は技術力を高めていきたいと思います。

最後まで読んでくださり、ありがとうございました。m(_ _)m

GENIEE TechBlog

Discussion