基礎力が鍵! Developers Boost 2025登壇レポート

こんにちは、ファインディのみっきー@mikiko_bridgeです。

12月6日(土)に池袋で開催されたDevelopers Boost 2025の「Hello, new world! ~技術とキャリアを次のステージへ~」というテーマのLT枠で登壇しました。

翔泳社さんのイベントで登壇するのは2回目です。昨年、Women Developers Summit 2024でLTをさせていただき、再び登壇の機会をいただけて本当に嬉しいです!

本記事では、私のLTの内容と、登壇準備を通じて得た気づきについてお伝えします。

ファインディと生成AI

ファインディでは、生成AIの活用を推進しています。

AI推進チームが設立され、エンジニアが開発に集中できる環境が整っています。AI推進チームがAIのキャッチアップや活用をサポートしてくれるため、最新技術を取り入れやすい環境です。

AI活用事例については、次のブログをご覧ください。

ジュニアエンジニアはどう生きるか?

生成AIが当たり前になった今、ジュニアエンジニアとしてどう成長していくべきでしょうか。これまでは、good first issue やテストコードの追加といった小さなタスクから始めて、徐々にスキルを身につけていくのが一般的でした。

しかし、生成AIの登場により、コードの自動生成やデバッグの支援が簡単にできるようになり、ジュニアエンジニアが直面する課題も変わってきています。

伸び悩むわたし

ファインディに転職してから、チーム目標である1日4件のプルリクエスト作成をほぼ達成できない日々が続いていました。

コードを書いても思うようにいかず、レビューで指摘される箇所も多く、「なんとなくうまくいかないな」という感覚が続きました。

同期入社のエンジニアたちが次々と新しい機能を実装していく中で、自分だけが取り残されているような焦りと不安を感じていました。

そんな状況を見かねて、テックリードの方がメンターとなり、毎日1on1をすることになりました。テックリードに声をかけられることはなかったので、1on1の予定が入った時はめちゃくちゃビビっていました。1on1の当日、怒られると思っていたのですが、そうではなく、今後どうやって成長していくべきかを真剣に話し合いました。

そして、5ヶ月間の修行が始まりました。私は、「あえて生成AIという便利なツールに頼ることなく、まずはエンジニアとしての基礎をしっかりと固める」という方針を選びました。

5ヶ月間、何をやったか

2024年12月から2025年4月までの約5ヶ月間、私はテストのリファクタリングとコードドキュメントの追加という地道な作業に集中的に取り組みました。テックリードの方がメンターとなり、毎日1on1を行い、進捗や課題について相談しました。

テストの追加

ファインディはテストカバレッジが90%超えを維持していますが、さらに堅牢なテストにするためのリファクタリングを行いました。

具体的には、ソート機能に関するテストを強化しました。

  • 境界値や閾値を意識したテストデータを用意する
  • ソート順が正しく機能していることを検証するため、ID順とは異なる順序でデータを配置し、意図した並び順になっていることを確認する
  • 条件に該当しないデータ(対象外となるケース)も含めることで、フィルタリングロジックが正しく動作していることを保証する

例えば、次のようなテストコードを書きました。

# ソート機能のテストの例
describe 'ソート機能のテスト' do
  let!(:user1) { create(:user, name: 'Charlie', created_at: 1.day.ago, is_active: true) }
  let!(:user2) { create(:user, name: 'Alice', created_at: 3.days.ago, is_active: true) }
  let!(:user3) { create(:user, name: 'Bob', created_at: 2.days.ago, is_active: true) }
  let!(:inactive_user) { create(:user, name: 'Dave', created_at: 4.days.ago, is_active: false) }

  it '名前順でソートされること' do
    result = User.active.order_by_name
    expect(result.map(&:name)).to eq(['Alice', 'Bob', 'Charlie'])
  end

  it '作成日順でソートされること' do
    result = User.active.order_by_created_at
    expect(result.map(&:name)).to eq(['Charlie', 'Bob', 'Alice'])
  end

  it '非アクティブなユーザーが除外されること' do
    result = User.active
    expect(result).not_to include(inactive_user)
    expect(result.count).to eq(3)
  end
end

初めはテストデータの作成ミスがあったり、想定以上に時間がかかったりしていました。レビューコメントをもらう数も多く、なかなか思うように修正が進まないこともありました。

しかし、徐々にフィードバックを活かして改善を重ねていくうちに、最終的にはテストケースの漏れを自分で見つけられるようになりました。

コードドキュメントの追加

テストの追加が進む中で、コードドキュメントの整備が課題として浮上しました。特に、内部実装の共通処理に関するドキュメントが不足していたため、こちらの整備に注力しました。

コードドキュメントの追加を始めた当初は、例外処理の仕様や実際の使用方法の理解に苦労し、作成に時間がかかることも多くありました。

具体的には、次のようなYARD形式のドキュメントを追加しました。 まず、コメントドキュメントがない状態のコードを見てみましょう。

class UpdateUserInteractor
  include Interactor

  delegate :user_id, :name, :is_active, :roles, :options, to: :context, private: true

  def call
    update_user
    context.user = user
  rescue ActiveRecord::RecordInvalid => e
    Logger.error_exception(e, message: 'Failed to update user')
    context.fail!(message: 'Failed to update user')
  end

  private

  def update_user
    # 実装
  end
end

このコードを見ただけでは、rolesには何が入るのか、optionsにはどんなパラメータを渡せばいいのか、よくわからないですよね?

そこで、YARD形式のコメントドキュメントを追加してみました。

# Interactorのコメントドキュメントの例
#
# @attr user_id Integer ユーザーID
# @attr name String 名前
# @attr is_active Boolean アクティブかどうか
# @attr roles Array<Role> 権限一覧
# @attr options Hash {
#   ids: Array<Integer> IDのリスト。
#   mode: String[Optional]("include") 選択モード
#   is_verified: Boolean (false) trueの場合、検証済みとして扱う
# }[Optional] オプション設定
#
# @example
#  UpdateUserInteractor.call(
#    user_id: 1,
#    name: 'John Doe',
#    is_active: true,
#    roles: [Role.first],
#    options: { ids: [1, 2, 3], mode: 'include', is_verified: true }
#  )
#
class UpdateUserInteractor
  include Interactor

  delegate :user_id, :name, :is_active, :roles, :options, to: :context, private: true

  # Interactor実行
  #
  # @return Interactor::Context {
  #   user: User 更新後のユーザーデータ
  #   message: String エラーメッセージ
  # } コンテキスト
  def call
    update_user
    context.user = user
  rescue ActiveRecord::RecordInvalid => e
    Logger.error_exception(e, message: 'Failed to update user')
    context.fail!(message: 'Failed to update user')
  end

  private

  def update_user
    # 実装
  end
end

いかがでしょうか?コメントがあると、各パラメータの型や意味、使用例が明確になって、格段にわかりやすくなりましたよね!

こうしたコメントドキュメントを追加したことで、自分自身がコードを読み返すときにも理解しやすくなりました。 後から参加する新メンバーにとっても助けになるし、生成AIにコードを解析してもらうときにも正確な情報を渡せるので、AI活用の場面でも役立っています!

対応が進むにつれて作業の質が上がり、自力も少しずつ付いてきたため、最終的にはテストケースの漏れを自分で見つけられるようになりました。

ファインディでは日報・週報の文化があり、テックリードからは「周りではなく過去の自分と比較しましょう」と言われてきました。過去の日報や週報を読み返してみると、2025年4月の週報に「修正が必要な箇所を見極める力がついてきた」という記述がありました。

自分の成長を客観的に実感できた瞬間でした。

結果

取り組みを始めた当初は、プルリクエストの作成が週に7.2件程度というペースで、レビューの数も多い状態でした。

2024/07/01〜2024/11/30までの1週間あたりにPR作成数

しかし、作業を続けていくうちに、徐々にコードの書き方やテストの構造に慣れてきて、最終的には1日あたり18件のプルリクエストを作成できるようになりました。

2024/12/01〜2025/04/30までの1週間あたりにPR作成数

現在とこれから

5ヶ月間の修行を通して、生成AIや目新しい技術の前に、まず基礎を固めることが大切だと実感しました。これからは、基礎力upをベースに生成AIを適切に活用しながら、より品質を高めていきたいと考えています。

現在は、生成AIをピンポイントで利用しています。以前と違って、出力結果を鵜呑みにはしていません。コードリーディングの補助や、命名の提案など、具体的なタスクに対して活用しています。

登壇資料

Speaker Deckで資料を公開しました。

「生成AIを"おあずけ"された私〜自力で書く力がついた半年間〜」 speakerdeck.com

おわりに

今回のLTでは、生成AIが当たり前になった時代において、ジュニアエンジニアとしてどう成長していくべきかについて、私自身の経験をもとにお話ししました。

生成AIは非常に強力で便利なツールですが、それを本当の意味で使いこなし適切に活用していくためには、基礎的な技術力やプログラミングの根本的な理解が不可欠だと感じています。

私はまだまだ成長途中ですが、この5ヶ月間の修行を通じて、焦らず地道に基礎を固めることの大切さを実感しました。同じようにキャリアをスタートした皆さんにとって、私の実践と学びが技術とキャリアを次のステージへ進めるヒントになれば幸いです。

最後に、このような貴重な機会をくださった翔泳社の皆さま、そして当日ご参加いただいた皆さまに心より感謝申し上げます。ありがとうございました!


ファインディでは共に働く仲間を募集中です!

興味がある方はこちらから↓ herp.careers