7
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

【自社開発1年目】「チーム経験ゼロ」の27歳元営業が、ダイレクト出版でAIを使い倒し本番コードを書くエンジニアになるまで

7
Posted at

TL;DR

  • 誰: 27歳元営業。エンジニア未経験でダイレクト出版のプロダクト企画部に入社して1年経過
  • やったこと: 大阪で2ヶ月研修 ➔ FE(TypeScript, React)➔ BE(Go)➔ FE(現在)
  • 感想: 結論、入社してよかった。やらかしもしたが、「失敗した時に何が起きるかまで考えてコードを書く力」がついた

1. 「チーム経験?ないです()」

前職はフツーの営業。その前は事務職。
エンジニアを目指した理由は、営業が嫌になって知り合いと相談して、『お前向いてそう』って言われたから。DM配信ツール作成とか営業リスト作成とかでコーディングは少しやってましたが、きっかけはそんなところです。

仕事では完全に世の流れに逆行したプロダクトを売っていたので、このまま経験が積めずに詰む気しかしていませんでした。資格を何も持っていなかったので、とりあえず休職しながら基本情報技術者 ➔ 簿記2級 ➔ FP3級 を脳死で取得。

転職となると3社目で、未経験だからあまり転職先に高望みはしていませんでした。
とある会社のチューターに真顔で言われた一言。

「あのさ、年齢 ÷ 10(2.6社)を超えると市場価値的に厳しいよ」

厳しすぎて顔がない。

チーム経験がなかったこともたまに響いた。

ワイ:「ペラペラペラ(捲し立てる)」
面接官:「ところで、チームで何かを成し遂げた経験はありますか?」
ワイ:「……ないです」
面接官:「……(にこやかだった顔が露骨に曇る)」

営業なんて個人の数字が全てだからね。


2. なぜダイレクト出版に入ったか ➔ 元上司の一言で即決

それでもなんとかSES複数社から内定をもらい、関係グループでお世話になった某大手企業のCTOからも「俺がエンジニアとして育てる」といありがたいお声があった。

そんな中届いたダイレクト出版のオファー。
転職活動中にカルチャーブックと行動規範「Basics」を読んで一番刺さっていたものの、「なんか会社がイケイケ風で爆死するのでは…?」と怯えてた。

どのルートもありえたけれど、決め切れなかったので深夜にCTOとLINEで相談した。

「SESはやめとけ。自社開発はいいぞ」

とダイレクト出版を推されて腹をくくった。自社開発で積める経験はSESでは補えないらしい。
当時は本当にそれでいいのか逡巡していたけど、今でもあの言葉に流されてよかったと思っている。
可能性を買ってくれた内定企業とCTOには感謝と辞退の連絡をいれた。


3. 大阪研修2ヶ月(過去のクソコードを晒して供養する)

入社してすぐにある仮想プロジェクト研修(2025/8/15〜9/26)は本社の大阪で行われた。
仮想プロジェクト研修は、未経験者が2~3名のチームで社内向けアプリをデザインから実装までを、1ヶ月という超短期間で完成させる鬼のスパルタ研修。

FastAPI + Next.js + MySQLで座席管理アプリ「ZASECKY」を作った。
実際のユーザー目線でUIやUXを考える研修もあった。実務に入った今でもその視点は忘れないようにしている。

こんな感じで付箋に貼ってUX・UIを考えていた

IMG_9550.JPG

DBの設計が終わったらエディタでガリガリと実際に実装を進めていく。
僕の担当:検索ボックス、WebSocketのドラッグ&ドロップ、アイコン、404ページ。

量産される産廃コード

ちなみに、当時どんなコードを書いていたかを振り返ってみると案外面白かった。
「動けばヨシ!」で量産した謎コードが、次の仮想PJの方々の学習に使われていた(しかも意図を訊かれていた)らしく、ただもう申し訳ない気持ちしかない。ここで黒歴史を供養させてほしい。南無三。

① 誰も呼ばない謎のAPIを生み出す

# app/routers/user_search_exact.py (コピペで置き換え)
@router.get("/search-exact", ...)
async def search_exact(
    name: str = Query(..., description="氏名(例:佐藤 花子)"),
    case_sensitive: bool = Query(False, description="Trueなら大文字小文字を区別"),
) -> List[Dict]:
    return await search_users_exact(db, name=name, case_sensitive=case_sensitive, space=space.value)

grep したら呼び出し0件。
検索ボックスをフロント側で全取得して処理する仕様になったのに、誰も使わないAPIを実装してた。虚無すぎる。

② 最大60件のAPIを同時爆撃 & エラー握りつぶし

// 約175行の怪文書 useEffect の一部
if (need > 0) {
  const pool = all.filter(u => !u.dept || (isLatin && !u.nameEn)).slice(0, 60);
  if (pool.length > 0) {
    await Promise.all(
      pool.map(p =>
        fetchUserDetailDto(p.id)
          .then(d => { /* 代入処理 */ })
          .catch(() => {}) // 👈 エラーを無の境地で捨てる
      )
    );

ヒット数が足りないと上限なしで60人分の詳細APIを連打。しかも .catch(() => {}) で失敗を隠蔽。エラーになった奴はサイレント消失。

③ ゾンビ化する setInterval

useEffect(() => {
  const connectWebSocket = () => {
    ws.current = new WebSocket(`${base}`);
    ws.current.onopen = () => {
      setInterval(() => { // 👈 クリアしてない()
        if (ws.current) ws.current.send(JSON.stringify({ type: 'ping' }));
      }, 60000);
    };
  };
  // ...
  return () => { if (ws.current) ws.current.close(); };
}, [base]);

WebSocket閉じるのに setInterval を止めてないから、画面移動するたびに裏でping送信タイマーが増殖していくホラー仕様。

今ならタイマーの ID を持っておいて、cleanup で clearInterval する。作ったものは自分で片付ける。

仮想PJの終わり

メンターの方々が手厚くサポートしてくださったおかげもあって、円満にZASEKKYは完成した。
(ドット風の社内マップを用意できなくて、Unityで作成しようと迷走もしたけど)
兎にも角にも、これまで技術書とか資格本で知らなかった知識が、実際の開発とリンクして大変意義のある研修だった。


4. 実務(東京配属)〜1文字の重み〜

仮想PJ後、2025年10月1日に東京チームへ合流。
テスト、サーバー側の開発、画面やコンポーネントの開発など、様々な開発に携わってきたと思う。

ざっくりやったこと

  • 12月〜: BE(Go)にアサイン。画像アップロードAPI(サイズ上限とEXIFの向き補正)、領収書のAPI
  • 2〜4月: 販売プランを増やしたり、マイページの機能を移植したり
  • 5〜7月: 決済関連
    • カード情報を自社サーバーに通さないトークン化と、3Dセキュアの2段階決済
    • 同じ決済リクエストが2回届いても1回しか通さない仕組み(Redis の GETDEL で15分だけ有効な鍵を使う)
    • カード連番の重複を防ぐ行ロック(SELECT ... FOR UPDATE)
    • Amazon Pay 連携、代理ログイン中は決済を 403 で止めるガード
  • 8〜9月: キャンペーン(FE)、Mixpanel の計測基盤構築

1文字の重み

ステージングでテストしていたら、新規クレジットカードの登録が落ちた。

原因は僕が5月に書いたこれ。

// 誤:0から始まる連番なのに「0」を不正値として弾いていた
if cardID <= 0 { ... }

カードの連番は0から始まる。なのに「0以下は不正」と書いたので、初めてカードを登録する人が全員弾かれる。
しかも画面には「カード情報をご確認のうえ再度お試しください」と出る。ユーザーは正しく入力しているのに、入力ミス扱いされる。

修正は <= を < にする1文字。テストは「連番0のカードが登録できる」ケースを足した。
コード1文字に責任を持つ重みを身体で理解した。
書いたコードの意図はなんなのか説明できることが求められる。
研修みたいに .catch(() => {}) で逃げることはできない。

たった1文字の違いだけど、その変更によって誰かにとって影響がある。(と、信じている)
中には大きな障害に発展するものもあるかもしれない。
それでも理想的な選択肢を詰めていく過程が凝り性の自分にとって面白かったりする。

余談

基本情報で学んだ知識が意外と出てくる。

  • DNS:メールアドレスのドメインの MX レコードを引いて、存在しないドメインは 400 で返す
  • 排他制御とトランザクション:カード連番の採番で行ロック、失敗したら全部ロールバック
  • CSRF とリプレイ攻撃:3DS のコールバックとリフレッシュトークンで、どの値を使い捨てにするか
    など。

6. AI(Claude Code / Gemini)との付き合い方

AIとの付き合い方も以前と変わった。

  • 1年前:「ChatGPT便利〜コピペ(完成版コピペコメントが残る失態)」
  • 現在:「Claude Codeに .steering 作らせてタスク単位で爆速実装」
    • BEのメインマージ52件中24件がClaudeとの Co-authored-by
    • チームのGoレビュー用AIスキル(ナレッジベース)をレビューコメント221件分析して 490件 ➔ 711件にアップデート(出典不明の3件は即削除)
    • チームのレビュー指摘492件を分析して、命名ガイドラインとBiomeのルールを作った。分析はAI、何をルールにするかは人間
    • 概念理解や学習はGeminiが一番分かりやすいのでGemini指名

手を動かす作業はAIに投げて、「失敗した時に何が起きるか説明する責任」を人間(僕)が持つスタイルに昇華した。


7. 開発環境・社風がよい

  • スペック: MacBook Pro(M4 Pro / メモリ48GB)貸与。

  • AI環境: Claude, Gemini, ChatGPTが使い放題(部署一元管理)。湧き出るインスピレーションから簡単にプロトタイプが作れる時代が到来している。

  • イベント: 読書会(最近だと『Refactoring UI』『部下としてのAI』とか)、約半年に1回の合宿(※業務です)

  • 20%ルール: 周囲の方を見ると、別PJや合宿の企画に費やしたりしている。(僕は通常業務に没頭しているので、使えてはいませんが。)

事務職の自分「8GBのMacBook Air動かないんですけど…画面に何も映らないままタイピングしてる…」
営業職の自分「売れないプロダクト売るのキツい…顧客からニーズを聞いているけど、プロダクトに反映できない…開発側に回りたい…」

環境も良ければ、自分の提案でプロダクトが日々改善されていく今の環境は、精神衛生面で望ましい。


8. まとめ:入社してよかった。

未経験で開発なんか自分にできる自信はなかったけど、東京配属2日目から始まったモブプロから始まって、毎日のレビュー、毎週のレトロ、1on1、そしてバグのリカバリーを経て、「失敗した時に何が起きるかまで考えてコードを書く力」が着実に身になっていっている。

できることが増えていく実感が、先の見えない毎日を耐える精神安定剤になっている。

PdMとかプロダクトを考える方に行くか、テックを極めるかはまだ決め切れていないけど、この会社ならどっちを選んでも面白そうな未来が待っていそう。

記事を読んで、興味をもっていたらぜひ採用サイト覗いてみて欲しい。


Links

7
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
7
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?