「コードが読めない!」海外転職したC#エンジニアが、グローバルチームで泣きながら作った「コード統一プレイブック」の話。

憧れの海外転職。しかし、僕を待っていたのは「読めないコード」のジャングルだった

(起承転結の「起」ここから)

どうも!皆さん、はじめまして。

とある国で、ITエンジニアとして働いている(C#とWPFで主にデスクトップアプリの設計・開発やってます)僕です。

「海外で働くエンジニア」って聞くと、どんなイメージがありますか?

「最先端の技術に囲まれて、多国籍なメンバーとスマートに議論を交わし、週末はカフェでMacBookを開いて優雅にコーディング…」

うんうん、わかります。僕もそうでした。日本でC#とWPFの経験を積んで、「よっしゃ、このスキルを世界で試してやるぜ!」と意気込んで、夢だった海外転職を果たしたわけです。

正直、最初は浮かれてました。新しい環境、新しい同僚、飛び交う英語(最初は冷や汗ダラダラでしたが)。「うわー、俺、グローバルなエンジニアじゃん!」って。

そう、あの日、あのコードベースを開くまでは。

僕の最初のタスクは、既存のWPFアプリケーションのパフォーマンス改善。日本では、MVVMパターンの設計やXAMLの最適化、非同期処理(async/await)あたりは、それなりに自信があった分野です。

「まあ、サクッと片付けますか!」

軽い気持ちでソリューション(.sln)を開き、プロジェクトの海を泳ぎ始めました。

…ん?

あれ…?

「え、なにこれ。読めない…」

いや、物理的に読めないわけじゃないですよ。C#はC#だし、XAMLはXAMLです。でも、そこに書かれていたのは、僕が知っている「C#の書き方」とは似て非なる、混沌とした「何か」でした。

まず、命名規則がカオス

  • _myVariable (アンダースコア派)
  • mMyVariable (ハンガリアン記法の名残? m_ 派)
  • myVariable (普通のキャメルケース派)
  • MyVariable (え、ローカル変数なのにパスカルケース…?)

これが、全部同じファイルに混在してるんです。

次に、設計思想がバラバラ

僕らのチームは、アメリカ、インド、ドイツ、中国、そして日本の僕、という構成。

  • あるドイツ人エンジニアのコードは、めちゃくちゃSOLID原則に忠実。抽象化レイヤーが何層にもなってて、一見すると「美しい」んだけど、シンプルな機能追加なのに10個のファイルを修正する必要がある、みたいな。
  • あるインド人エンジニアのコードは、良くも悪くも「動けば正義」。ViewModelのコンストラクタでDB直叩きしてたり、Viewのコードビハインド(.xaml.cs)に数千行のビジネスロジックが書いてあったり。
  • あるアメリカ人エンジニアは、最新のDI(依存性注入)ライブラリやRx(Reactive Extensions)を使いたがる。便利だけど、他のメンバーがそれを理解してなくて、結局レガシーなやり方と混在して、もっとカオスに。

僕が日本で学んだ「丁寧な実装」「暗黙のルール(阿吽の呼吸)」は、そこにはありませんでした。

日本だと、WPFアプリを作るなら「Prism使うよね」「ViewModelのベースクラスはこれだよね」「エラー処理はこう書くよね」みたいな、チーム内(あるいは業界内)の「型(カタ)」がある程度決まってませんか?

でも、グローバルチームは違います。それぞれが「自分の国で」「自分の経歴で」学んできた「ベストプラクティス」が、全部違うんです。

これは、技術力の問題じゃない。文化と背景の問題なんです。

最初の1ヶ月、僕は「コードを読む」だけで1日が終わることもザラでした。パフォーマンス改善どころか、バグを1個直すのに、スパゲッティのように絡まったコードを解読するだけで疲弊困憊。

「やばい。このままじゃ、俺、海外に来た意味がない。ただの『コード解読おじさん』だ」

焦りました。そして、同時にこう思ったんです。

「これって、僕だけが困ってることじゃないよな? チーム全員、この『読みにくさ』のせいで、開発スピードが劇的に落ちてるんじゃないか?」

そう。これが、海外エンジニアとして僕がぶち当たった最初の、そして最大の壁でした。

技術力? 英語力? そんなもの、この「コードのバベルの塔」の前では、二の次、三の次でした。

僕が本当にやるべきことは、自分のタスクをこなすことじゃなく、「チーム全員がハッピーに開発できる『共通言語』=『コーディング規約』を作ることだ」 と気付いたんです。

でも、これが地獄の始まりでした。

「俺のやり方がベストだ!」と信じて疑わない、各国の猛者たちをどうやって説得するのか?

「ルールを増やすな、生産性が落ちる」というマネージャーをどう言いくるめるのか?

このブログシリーズでは、僕がこのカオスなグローバルチームで、どうやって「コードの標準化」を進めていったのか、その実体験ベースの「戦術」と「人生術」を、余すところなくお伝えしようと思います。

題して、「Your Global Code Playbook」

このシリーズを読み終える頃には、あなたは単なる「コードが書けるエンジニア」ではなく、「カオスなチームを『導ける』エンジニア」になるための、具体的なヒントを掴めているはずです。

今回の「起」では、僕が直面したリアルな「絶望」をお伝えしました。

次回、「承」では、この混沌としたコードベースを前に、僕がまず取り組んだ「ある役割」についてお話しします。これが、この戦いの最初の「一手」になりました。

カオスを制す「たった一つの役割」。僕は”コード番長”になることにした

(起承転結の「承」ここから)

どうも!「起」の記事([前回の記事リンクなど想定])は読んでいただけましたか?

夢の海外転職を果たした僕を待っていたのは、アメリカ、インド、ドイツ、中国…と、メンバーの国の数だけ「書き方(流儀)」が存在する、WPFの混沌としたコードベース。

「このままじゃ、バグ修正どころか、コードを読むだけで日が暮れる。チームが沈む…!」

本気で焦った僕は、「なんとかしなきゃ」と立ち上がるわけです。

…そして、見事に最初の「やらかし」をします。

海外転職したエンジニアが、一番やりがちで、一番(人間関係的に)コケる失敗。

それは、「自分が信じる『正義(ベストプラクティス)』を、そのままチームに押し付けようとすること」 です。

当時の僕は、日本で培ったC#とWPFの経験(特にMVVMの「あるべき論」)に、それなりの自負がありました。だから、チームのコードレビューで、こう指摘しちゃったんです。

「(ドイツ人の同僚のコードに対して)この抽象化はやりすぎじゃない? もっとシンプルに書けるよ」

「(インド人の同僚のコードに対して)ViewModelで直接DBを叩くのはMVVMの原則に反してる。Repositoryパターンを使うべきだ」

はい、最悪ですね(笑)

結果、どうなったか?

ドイツ人の同僚からは「君はSOLID原則を知らないのか? 長期的な保守性(Maintainability)を考えろ」と3倍の長さのコメントで返され、

インド人の同僚からは「動いている(It works.)のに、なぜ変える必要がある? 君のやり方は工数がかかる」と、あからさまに不機嫌な顔をされました。

技術的には、僕の指摘が100%間違っていたわけじゃないかもしれません。

でも、彼らにとっては**「昨日今日入ってきた日本人が、俺のやり方にケチをつけてきた」**としか映らなかったんです。

ここで学んだ、海外で働くための人生術その1

正論は、武器じゃない。

グローバルチームにおいて、技術的な「正しさ」は、国や文化、個人の経験によって尺度がバラバラ。自分の「正義」を振りかざした瞬間、あなたは「敵」認定されます。

僕は気づきました。

彼らを「論破」しても、チームは良くならない。むしろ雰囲気は最悪になる。

問題は「コードが間違っていること」じゃない。

問題は**「コードがバラバラなせいで、全員の生産性が落ち、レビューでイライラし、バグが生まれ、みんなが不幸になっていること」**です。

じゃあ、どうする?

僕がやるべきことは、彼らを「正す」ことじゃない。

「このカオス、なんか面倒くさくないですか? みんなで少しだけ楽になりませんか?」と、「共通の敵(=カオス)」を提示することだったんです。

そこで僕は、次のチームミーティングで、思い切って手を挙げました。

「ちょっと提案があるんだけど」

「今、僕らのコードベースって、正直、読むのが大変じゃない? Aさんの命名規則と、Bさんの設計パターンが違うから、新しい機能を追加するときに、どっちに合わせるか迷ったり、レビューで時間がかかったりしてると思うんだ」

(チームメンバー、数人が頷く)

「だから、この『バラバラ感』を解消するための『係』をやりたい。

僕がルールを決めるんじゃないよ。みんなの『こうあるべき』という意見を集約して、最小限の『共通ルール(たたき台)』を作るファシリテーター(調整役)をやらせてほしい」

「最終的には、新しい人がチームに入ってきたときに『これ読んでおいて』って渡せるような、シンプルな『プレイブック』を作りたいんだ。どうかな?」

僕は、この役割を**「Code Consistency Champion(コード統一推進担当)」**と呼びました。

…まあ、カッコつけて横文字使ってますけど、要は「コード番長」です。

マネージャーは、最初「うーん、ルールで縛ると開発速度が落ちないか?」と渋い顔をしました。

すかさず僕は、こう返します。

「逆です。ルールがないから、今、レビューで無駄な議論(さっきの僕の失敗みたいな)が起きて、速度が落ちてるんです。僕らが議論すべきは『この書き方(Syntax)が好きか嫌いか』じゃなくて、『この機能がユーザーに価値を届けるか(Value)』のはずですよね?」

この一言が効きました。

「確かに(That’s true.)」とマネージャー。

こうして、僕は正式に「コード番長」としての活動を許可されたのです。

人生術その2

「役割」を自ら定義しろ。

海外の現場では、「指示待ち」は評価されません。「問題」を見つけたら、「解決策」と「そのために自分が必要な役割(と権限)」をセットで提案する。

「ルールを作りたい」ではなく、「チームの生産性を上げるための『調整役』をやる」と宣言する。これが「オーナーシップ」ってやつです。

さて、「コード番長」になった僕が、まずやったこと。

それは、「コーディング規約(100ページ)」を作り始めること…ではありません。

僕がやったのは、「チーム全員の『不満』を聞いて回ること」 でした。

番長(Champion)の仕事は、独裁者(Dictator)になることじゃない。チームの「声」を拾い上げることです。

僕は、主要なエンジニア(特に、あのドイツ人とインド人の同僚)と1on1の時間を設け、こう聞きました。

「(PCの画面を見せながら)ぶっちゃけ、今のコードベースで『一番ムカつく』のって、どこ?」

これが効果てきめんでした。

  • ドイツ人の同僚(品質重視派):「このViewModel! テストが書けないじゃないか! Viewへの依存が強すぎる。あと、エラーハンドリングが全部 try-catch のベタ書きで、いつどこで例外が握りつぶされてるか分からない!」
  • インド人の同僚(速度重視派):「(ドイツ人のコードを指して)このクラス、インターフェースが多すぎて、たった1つのメソッドを追うのに5つのファイルを開かないといけない! シンプルなCRUD(作成・読み取り・更新・削除)なのに、なぜこんなに複雑なんだ!」
  • アメリカ人の同僚(新技術好き派):「そもそも、未だに古いイベントハンドラ(.xaml.cs)を使ってるのが信じられない。WPFなら ICommand を使うべきだし、DI(依存性注入)コンテナも導入すべきだ」

出るわ出るわ、不満の嵐。

でも、これが超重要だったんです。彼らは「自分の意見(正義)」を、まず僕に吐き出すことができた。

僕はそれをジャッジせず、ただ「うんうん、わかるよ」「なるほど、確かにそれ読みにくいね」と、ひたすら共感(Empathy)し、メモを取りました。

人生術その3

人は「正論」では動かない。「共感」で動く。

相手を変えようとする前に、まず相手の「痛み」や「主張」を徹底的に理解する。

「あなたの言いたいことは、ちゃんと受け止めたよ」という姿勢を見せるだけで、相手は次のステップ(=妥協や議論)に進む準備ができます。

全員のヒアリングを終えて、僕は「共通の敵」を見つけ出しました。

それは、「抽象化レベルがバラバラ」「命名規則がカオス」「エラー処理が場当たり的」という、まさに僕が最初に感じた違和感そのものでした。

ただ、今回は「僕がそう思う」ではなく、**「チーム全員が(程度の差こそあれ)そう思っている」**という「お墨付き」を得たことが決定的に違います。

僕は、集めた不満をベースに、次のアクションを起こしました。

いきなり100個のルールは作りません。そんなもの、誰も守らないから。

僕が提案したのは、「Minimum Viable Rules(実用最小限のルール)」 です。

まずは、全員が「まあ、それなら…」と同意できる、たった3つのルールから始めることにしたんです。

  1. 命名規則(これだけは統一しようぜ)
    • プライベートフィールド: _camelCase (ドイツ兄貴の m_ も、インド兄貴の camelCase も捨ててもらい、C#の公式ガイドラインに寄せた)
    • ローカル変数: camelCase
    • メソッド・プロパティ: PascalCase
  2. async/await のお作法
    • ViewModelやビジネスロジックでは、原則 ConfigureAwait(false) を付ける。(UIスレッドに戻る必要がない場所でのデッドロックを避けるため。これはWPF/WinForms開発では超重要!)
  3. XAMLの Binding の書き方
    • ElementName でのBindingは原則禁止。(ViewModelのプロパティと疎結合にするため)
    • RelativeSource や DataContext 経由でのBindingを推奨する。

たったこれだけです。

設計思想(SOLID原則 vs シンプルさ)のような「宗教戦争」になりかねない部分は、あえて(今は)放置しました。

まずは、誰が見ても「Yes/No」で判断できる、具体的な「書き方(Syntax)」から統一することにしたんです。

人生術その4

完璧なスタートを目指すな。「60点の合意」で走り出せ。

グローバルチームでの合意形成は、全員が100%満足する地点を目指すと永遠に終わりません。

「全員が『まあ、これなら許せる』という60点のライン」を見つけ、まず実行する。小さな成功体験(=コードがちょっと読みやすくなった!)を積むことが、次の大きな改善(=設計思想の統一)への第一歩になります。

僕は、この「最小限ルール」をドキュメント(Confluence)にまとめ、チームに共有しました。

「よし! これで明日からコードが綺麗になるぞ!」

「コード番長、ミッションコンプリート!」

…と、もちろん、そんなに甘くはありませんでした。

ルールは作られました。ドキュメントも整備されました。

しかし、数日後、コードレビューのキュー(Pull Request)に流れてきたのは、見事にルールを無視した、いつも通りのカオスなコードだったのです。

「あれ…? 誰もルール読んでない…?」

ドイツ人の同僚は相変わらず抽象化レイヤーを作りまくり(これはルール外だからOK)、インド人の同僚は平気で _myVariable じゃない命名(myVariable)を使っていました(これはルール違反)。

僕は、PRにコメントしました。

「(インド人の同僚へ)お疲れ! この変数名、_myVariable に変えてもらえる? 先週決めたルールだから」

返ってきたコメント。

「(一言)Why?(なんで?)」

僕は、カチンと来ました。

(いや、決めたじゃん! ミーティングいたじゃん!)

ルールを「作ること」は、スタートラインに過ぎませんでした。

本当の地獄は、ルールを「浸透」させ、「守ってもらう」ことにあったのです。

僕はただの「うるさい規約おじさん」になってしまうのか?

それとも、チームを本当に「変える」ことができるのか?

「承」では、僕が「コード番長」という役割を立ち上げ、最小限のルール(たたき台)を作るまでの「試み」と「最初の挫折」をお話ししました。

次回、「転」では、この「誰も守らないルール」という壁をどう乗り越えたのか。

フックにあった「コード監査(Auditing)」と、僕が導入した「ある仕組み」について、具体的なステップをお話しします。これが、僕らのチームの転換点になりました。

ルールは「作る」な、「発見」させろ。コード監査で見えた「チームのクセ」と「パフォーマンスのボトルネック」

(起承転結の「転」ここから)

「Why?(なんで?)」

「承」の最後。僕が(チームで合意したはずの)最小限のルール(命名規則)を守っていないPRに対して、「ルールだから直して」とコメントした時、インド人の同僚から返ってきた、たった一言。

この「Why?」は、僕の心を折るには十分すぎました。

(え、ミーティングで合意したじゃん…なんで今さら「Why?」なんだよ…)

ここで僕が取り得た選択肢は3つ。

  1. 戦う:「ルールはルールだ」と、マネージャーを巻き込んで強制する。→ 確実に人間関係は破綻。僕は「独裁者(Dictator)」のレッテルを貼られ、チームは崩壊する。
  2. 諦める:「あ、ごめん。そのままでいいや」と、ルールを撤回する。→ カオスに戻るだけ。僕の「コード番長」としての信頼はゼロになり、この問題は永遠に解決しない。
  3. 戦略を変える:彼が「Why?」と聞かなくても済む「理由」を探す。

僕は、3を選びました。

僕は、彼にこう返信しました。

「Good question!(良い質問だね!) ちょっと考えさせてくれ。次のミーティングで、このルールが『なぜ』必要なのか、もう一度みんなで話さないか?」

僕は、カチンときた感情をぐっと抑えました。

彼が悪いんじゃない。「ルールを守るメリット」を、僕がちゃんと伝えきれていなかったんだ。

人生術その5

相手の「Why?」は、攻撃じゃない。「納得したい」というサインだ。

(特に欧米のエンジニアは)ルールや指示に対し、「その背景(Rationale)は何か?」を常に問います。これは反抗ではなく、ロジカルに納得した上で行動したい、というプロ意識の表れ。

「決まりだから」は、世界で一番通用しない理由です。

僕は気づきました。

「コードを綺麗にしたい」というのは、しょせん僕個人の「好み」や「美学」のレベルを出ていなかったのかもしれない。

彼ら(ドイツ人、インド人、アメリカ人)を動かすには、**「好み」ではなく、全員が無視できない「客観的な事実(データ)」**が必要だと。

そこで僕は「コード番長」として、次の提案をしました。

「みんな、自分のコードが『読みにくい』って言われるのは気分が悪いよな。僕もそうだ」

「だから、『誰のコードが悪いか』を探すのはもうやめよう。代わりに、僕らの『製品(WPFアプリ)』が、今どれだけ『病気』にかかっているか、健康診断(Code Audit)をしないか?」

「健康診断」という言葉が効きました。

「僕の『主観』でレビューするんじゃなく、ツール(静的解析)を使って、客観的に『ヤバい箇所』をリストアップするんだ。特に、顧客からクレームが多い『パフォーマンス問題』や『アプリが固まる(フリーズ)』現象に絞って監査(Audit)しよう」

これには誰も反対しませんでした。「製品を良くする」ことは、全員の共通目標だからです。

僕は「コード番長」から、一時的に「コードの医者」になりました。

これが、僕らのチームの**「転換点」**になります。

僕が実行した「コード健康診断(Audit)」の具体的なステップはこうです。

ステップ1:客観的な「診断ツール」を導入する

僕の「主観」を排除するため、まずはC#(WPF)の世界で鉄板のツールをCI(継続的インテグレーション)プロセスに組み込みました。

  • Roslyn Analyzers (.NET Compiler Platform):Microsoftが公式に出しているコード解析ライブラリ。async/await の不適切な使い方(async void の乱用など)や、WPF特有のメモリリークの温床になるコード(イベントハンドラの解除漏れなど)をビルド時に警告してくれます。
  • SonarQube (or SonarLint for IDE):コードの「健康状態」をダッシュボードで可視化してくれるツール。「コードの匂い(Code Smells)」、「バグの可能性」、「技術的負債(Technical Debt)」を客観的な「時間(=修正にかかる時間)」や「深刻度(Blocker, Critical…)」で示してくれます。

僕はまず、これらのツールをローカルで動かし、現状のコードベースをスキャンさせました。

…数分後。出てきた結果を見て、僕は(いろんな意味で)笑顔になりました。

「お宝(負債)の山だ…!」

ステップ2:問題を「ビジネスの痛み」で分類する

ツールは、何千もの「警告」を吐き出します。

これを全部見せても、チームは「うわ、面倒くさい」と思うだけ。

大事なのは、これを「ビジネス上の痛み」と「顧客の不満」に紐づけて分類することです。

僕は、警告の山を、特に以下の3つのカテゴリに絞って整理しました。(フックにあった international performance issues を意識しています)

  1. UIフリーズ(応答なし)を引き起こす「時限爆弾」
    • async void の乱用: 例外が握りつぶされ、アプリが「何も言わずに」死ぬ原因。
    • UIスレッドでの重い処理: Task.Result や .Wait() で、非同期であるべき処理を同期的に待ってしまい、画面がガチガチに固まるコード。
  2. アプリを重くする「メモリリーク」の温床
    • WPF特有の INotifyPropertyChanged の実装ミスや、イベントハンドラの登録しっぱなし。
    • 巨大すぎるViewModel(例の数千行のコード)が、不要になってもGC(ガベージコレクション)に回収されず、メモリに居座り続ける問題。
  3. 国際化(i18n)対応の「地雷」
    • コード内にハードコードされた文字列(”OK”, “Cancel”, “Error: …” など)。
    • 日付や通貨のフォーマットが、ユーザーのカルチャ(国・地域設定)を無視して固定("yyyy/MM/dd" など)になっている箇所。

ステップ3:「犯人探し」ではなく「問題の可視化」として発表する

そして、運命のチームミーティング。

僕は、ツールのダッシュボードと、僕がまとめた「トップ3のヤバいカテゴリ」をプロジェクターに映し出しました。

「さて、これが僕らのコードベースの『健康診断結果』だ」

シーン…と静まり返る会議室。

僕は、あえて「誰が書いたか」には一切触れず、淡々と「事実」を読み上げました。

「まず、SonarQubeのレポートによると、**『技術的負債』は合計で『120人日』**と見積もられている。これは、フルタイムのエンジニアが6ヶ月間、バグ修正だけにしがみつく必要がある量だ」

「次に、パフォーマンス。顧客から『アプリが固まる』とクレームが来ているトップ5の画面。Roslyn Analyzerによると、その5つの画面すべてで、async void が不適切に使われていることがわかった」

「そして、メモリ。アプリの起動が遅く、使い続けると重くなる問題。メモリ使用量がトップのViewModelトップ10をリストアップした。これらは密結合すぎて、ユニットテストが1行も書かれていない

この瞬間、あの「Why?」と言ったインド人の同僚と、「抽象化こそ正義」と言っていたドイツ人の同僚が、顔を見合わせたのを僕は見逃しませんでした。

async void を多用していたのは、主に「速度重視」のインド人同僚でした。

テスト不能なほど複雑でメモリを食うViewModelを作っていたのは、皮肉にも「品質重視」のドイツ人同僚のコードでした。

僕は、ここで初めて「ルール」の話を持ち出しました。

「思い出してほしい。僕らが決めた『最小限のルール』。

例えば、『命名規則を _camelCase に統一する』。

これは、ただの『好み』じゃない。SonarQubeのようなツールが、フィールドなのかローカル変数なのかを正しく『認識』し、技術的負債を正確に『自動検出』するための、**最低限の『規律』**なんだ」

「**『async/await を正しく使う』というルール。

これは、まさにさっき見た『UIフリーズ』という『顧客の痛み』**に直結していた」

「Why?(なんで?)」

その答えは、「僕がそう決めたから」じゃない。

「そうしないと、ツールが負債を検知できず、顧客が迷惑し、そして(テストが書けなくて)未来の自分たちが苦労するからだ」

これが、僕が提示した「客観的な理由」でした。

ミーティングが終わる頃、あのインド人の同僚が僕のところにやってきました。

「…Hey。さっきのレポート、すごいな(That’s insightful.)。

あの async void の警告、俺のIDE(Visual Studio)でもリアルタイムで見れるようにできないか?」

「転」が「起」に変わった瞬間でした。

僕は、心の中でガッツポーズしました。

人生術その6

ルールに「意味」を与えろ。

「ルールを守れ」ではなく、「ルールが守るもの(=品質、パフォーマンス、未来の工数)」を示せ。

ルールは「罰」ではなく、チーム全員が楽になるための「投資」だと理解されたとき、初めて文化として根付く。

「ルールを破った人」を吊し上げるのではなく、「ルールの必要性」をデータで証明する。

僕の「コード番長」としての本当の仕事は、ここから始まりました。

チームは「なぜルールが必要か」を(ようやく)理解しました。

でも、人間は忘れる生き物です。そして、忙しいと、分かっていてもルールを破ってしまう。

じゃあ、どうやってこの「良い流れ」を「仕組み化」し、「文化」として定着させていくのか?

僕らの「コード統一プレイブック」は、まだ完成していません。

次回、「結」では、この監査(Audit)結果を元に、僕らがどうやってルールを「自動化」し、レビュープロセスを改善し、そして「進化し続けるプレイブック」を作り上げたのか。

その最終章と、海外エンジニアとして学んだ「チームで勝つ」ための人生術について、お話しします。

完璧なルールは存在しない。僕らの「プレイブック」が生き残り続ける理由

(起承転結の「結」ここから)

どうも!長かったこのシリーズも、ついに最終回です。

「起」で、多国籍チームのコードの混沌(カオス)に絶望し、

「承」で、僕は「コード番長(Champion)」として立ち上がるも、「Why?(なんで?)」の壁にぶつかり、

「転」で、僕は「主観」を捨て、「客観的なデータ(コード監査)」という武器を手に入れ、チームの「Why?」に対する答え(=顧客の痛みや未来の工数)を提示しました。

あのミーティングの後、僕に「俺のIDEでも警告(async void のやつ)見れるようにできないか?」と聞いてきたインド人の同僚。

僕は、彼に(そしてチーム全員に)、Visual Studioに SonarLint という拡張機能を入れる方法と、リポジトリに .editorconfig ファイル(全メンバーのIDE設定を統一する魔法のファイル)を追加する方法を共有しました。

これが、第二の「転換点」でした。

ルールが「ドキュメント(Confluence)に書いてある『お説教』」から、「今まさに書いている瞬間に、IDEが教えてくれる『相棒(アシスタント)』」に変わった瞬間でした。

人間、弱いんです。僕だって忙しければ「えいや!」でルールを破りたくなる。

でも、書いた瞬間にエディタ上で赤い波線(警告)が出たら?

「あ、やべ。_camelCase にしなきゃ」

「あ、async void じゃなくて async Task にしなきゃ」

そう。ルールは「記憶」させるものじゃない。「仕組み」で守らせるものなんです。

僕は、この流れを一気に加速させました。

「コード番長」としての、僕の最後の仕上げです。

仕上げその1:「僕」をレビュープロセスから排除する

僕は、もう「規約おじさん」としてPR(Pull Request)にコメントしたくありませんでした。感情的な対立はもうウンザリです。

そこで、CI/CDパイプライン(Azure DevOpsを使ってました)に、SonarQubeの「クオリティゲート(Quality Gate)」を組み込みました。

これは、PRが作られるたびに自動でコードをスキャンし、「ヤバいコード」が追加されていたら、「僕」ではなく「システム(ボット)」が、PRを自動的に「Fail(失敗)」させる仕組みです。

  • 新しい async void が追加されたら、Fail。
  • テストカバレッジが一定以下になったら、Fail。
  • コードの重複率が上がったら、Fail。

僕の仕事は、PRで「ルール違反だ!」と指摘することから、「このPR、クオリティゲートでFailしてるけど、どうした? 何か困ってる?」と、相手を「助ける」ことに変わりました。

指摘するのが「人」から「システム」に変わっただけで、チームの心理的安全性(Psychological Safety)は劇的に改善しました。

人生術その7

「意志」に頼るな、「仕組み」を作れ。

「頑張ってルールを守ろう」という精神論は、グローバルチームでは(というか、どこでも)機能しません。

人間は忘れるし、サボる生き物だ、という前提に立つ。

「頑張らなくても、自然とルールが守られてしまう環境」を設計すること。それこそが、エンジニアリング(工学)です。

仕上げその2:「聖書」ではなく「Wiki」を作る

ルールと仕組みはできました。

でも、これで完成か? いいえ、違います。

もし、このルールが「一度決めたら絶対に変えられない『聖書(Bible)』」だったら、僕らのチームは1年後、間違いなく「新しい技術に適応できない、老害チーム」になっていたでしょう。

技術は進化します。C#にも新しい構文(例えば record 型とか)がどんどん追加されます。

「ルールが古いから、新しい書き方ができない」なんて、本末転倒です。

そこで僕は、「コード番長」としての最後の仕事として、**「コード番長会議(Code Consistency Meeting)」**という、月イチの定例ミーティングを設定しました。

メンバーは、僕、ドイツ人(品質重視)、インド人(速度重視)、アメリカ人(新技術好き)の4人。

この会議の目的はただ一つ。

「僕らの『プレイブック(ルール)』を、僕らの『手で』、常に最新版にアップデートし続けること」

アジェンダはこんな感じ。

  • 「先月のSonarQubeの監査レポート、見てみよう。負債、減ってるね!」
  • 「最近、このルール(例:DIコンテナの使い方)が現状と合ってなくない? もっと良い書き方、誰か知らない?」
  • 「新しいライブラリ(MediatR とか)導入したいんだけど、既存のルールとぶつからないか、ここで議論しよう」

これが、僕らが手に入れた**「イテレーティブな(反復的な)アプローチ」**です。

(フックにあった The iterative approach ってやつですね)

「転」で保留にしていた「設計思想(宗教戦争)」、覚えてますか?

ドイツ兄貴の「SOLID原則ガチガチ」 vs インド兄貴の「シンプルイズベスト」。

この「コード番長会議」と「監査データ」が、ついにこの宗教戦争にも決着を(というか、和解を)もたらしました。

僕らは「どっちが正しいか」ではなく、**「どの画面(機能)に、どの設計を適用すべきか」**という議論ができるようになったんです。

  • 顧客情報(Personal Data)を扱うような、変更頻度が高く、テストが絶対に不可欠なコア機能→ ドイツ兄貴の言う通り、SOLID原則と抽象化をしっかり適用する。
  • 一時的なキャンペーン情報を表示するだけのような、使い捨てに近いシンプルな機能→ インド兄貴の言う通り、速度重視でシンプルな実装にする。ただし、async void は使わない(クオリティゲートでFailするから)。

僕らは、「銀の弾丸(=常に正しい、たった一つの設計)」など存在しないことを学びました。

人生術その8

「完璧なルール」を目指した瞬間、それは「負債」になる。

ルールは、チームを「守る」ためにあるのであって、「縛る」ためにあるのではない。

環境(技術、メンバー、ビジネス要件)が変われば、ルールも変わるのが当たり前。

「一度決めたこと」にしがみつくのではなく、「変わり続ける勇気」を持つこと。それが「アジャイル」であり、グローバル環境で生き残る「適応力」です。


【結】僕らが手に入れたもの、そしてあなたへ

このブログシリーズを始めた時、僕は「海外転職したC#エンジニア」でした。

そして今、僕は「カオスな多国籍チームの『共通言語』を作ったエンジニア」になりました。

僕がやったことは、高度なC#のテクニック(メタプログラミングとか)を駆使したことではありません。

やったことは、

  1. 観察し(Observe): チームがカオスで苦しんでいることに気づき、
  2. 定義し(Define): 「コード番長」という役割を自ら提案し、
  3. 実行し(Execute): 監査(Audit)という「客観的データ」を収集し、
  4. 反復する(Iterate): 「クオリティゲート」と「定例会議」という「仕組み」に落とし込む。

これだけです。

僕が作った「コード統一プレイブック」の中身(C#の命名規則とか)は、あなたのチームでは役に立たないかもしれません。

でも、この**「プレイブックの『作り方』」**は、あなたが世界のどこで、どの言語(PythonでもJavaでも)を使っていても、絶対に役に立つと信じています。

なぜなら、海外(グローバル)で働くエンジニアに本当に求められるのは、「コードが書ける能力」だけじゃないから。

「背景が全く違う人たちと、どうやって『合意』を形成し、『共通のゴール』に向かう『仕組み』を設計できるか」

この能力こそが、あなたを「替えの効かないエンジニア」にしてくれます。

コードは、書く時間よりも、読まれる時間の方が圧倒的に長い。

ましてや、それを読むのが、あなたと全く違う教育を受けてきた、違う国のエンジニアなら、なおさらです。

「読めないコード」は、技術的負債であると同時に、「コミュニケーションの負債」なんです。

これから海外で働こうとしているあなたへ。

技術力と英語力はもちろん大事です。でも、それと同じくらい、「カオスを構造化する力」を磨いてください。

あなたが新しいチームに入った時、もしそこが「カオス」だったら…

それは、絶望する場所じゃない。

それは、あなたが「コード番長(Champion)」として、チームを救うヒーローになれる、最高の「チャンス」です。

僕のこの「グローバルコードプレイブック」の話が、あなたの「人生術」として、何か一つでもヒントになれば、こんなに嬉しいことはありません。

最後まで読んでくれて、本当にありがとう!

またどこかの国の、どこかのコードベースでお会いしましょう!

コメント

タイトルとURLをコピーしました