憧れの海外転職。しかし、僕を待っていたのは「読めないコード」のジャングルだった
(起承転結の「起」ここから)
どうも!皆さん、はじめまして。
とある国で、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つのルールから始めることにしたんです。
- 命名規則(これだけは統一しようぜ)
- プライベートフィールド:
_camelCase(ドイツ兄貴のm_も、インド兄貴のcamelCaseも捨ててもらい、C#の公式ガイドラインに寄せた) - ローカル変数:
camelCase - メソッド・プロパティ:
PascalCase
- プライベートフィールド:
async/awaitのお作法- ViewModelやビジネスロジックでは、原則
ConfigureAwait(false)を付ける。(UIスレッドに戻る必要がない場所でのデッドロックを避けるため。これはWPF/WinForms開発では超重要!)
- ViewModelやビジネスロジックでは、原則
- 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つ。
- 戦う:「ルールはルールだ」と、マネージャーを巻き込んで強制する。→ 確実に人間関係は破綻。僕は「独裁者(Dictator)」のレッテルを貼られ、チームは崩壊する。
- 諦める:「あ、ごめん。そのままでいいや」と、ルールを撤回する。→ カオスに戻るだけ。僕の「コード番長」としての信頼はゼロになり、この問題は永遠に解決しない。
- 戦略を変える:彼が「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 を意識しています)
- UIフリーズ(応答なし)を引き起こす「時限爆弾」
async voidの乱用: 例外が握りつぶされ、アプリが「何も言わずに」死ぬ原因。- UIスレッドでの重い処理:
Task.Resultや.Wait()で、非同期であるべき処理を同期的に待ってしまい、画面がガチガチに固まるコード。
- アプリを重くする「メモリリーク」の温床
- WPF特有の
INotifyPropertyChangedの実装ミスや、イベントハンドラの登録しっぱなし。 - 巨大すぎるViewModel(例の数千行のコード)が、不要になってもGC(ガベージコレクション)に回収されず、メモリに居座り続ける問題。
- WPF特有の
- 国際化(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#のテクニック(メタプログラミングとか)を駆使したことではありません。
やったことは、
- 観察し(Observe): チームがカオスで苦しんでいることに気づき、
- 定義し(Define): 「コード番長」という役割を自ら提案し、
- 実行し(Execute): 監査(Audit)という「客観的データ」を収集し、
- 反復する(Iterate): 「クオリティゲート」と「定例会議」という「仕組み」に落とし込む。
これだけです。
僕が作った「コード統一プレイブック」の中身(C#の命名規則とか)は、あなたのチームでは役に立たないかもしれません。
でも、この**「プレイブックの『作り方』」**は、あなたが世界のどこで、どの言語(PythonでもJavaでも)を使っていても、絶対に役に立つと信じています。
なぜなら、海外(グローバル)で働くエンジニアに本当に求められるのは、「コードが書ける能力」だけじゃないから。
「背景が全く違う人たちと、どうやって『合意』を形成し、『共通のゴール』に向かう『仕組み』を設計できるか」
この能力こそが、あなたを「替えの効かないエンジニア」にしてくれます。
コードは、書く時間よりも、読まれる時間の方が圧倒的に長い。
ましてや、それを読むのが、あなたと全く違う教育を受けてきた、違う国のエンジニアなら、なおさらです。
「読めないコード」は、技術的負債であると同時に、「コミュニケーションの負債」なんです。
これから海外で働こうとしているあなたへ。
技術力と英語力はもちろん大事です。でも、それと同じくらい、「カオスを構造化する力」を磨いてください。
あなたが新しいチームに入った時、もしそこが「カオス」だったら…
それは、絶望する場所じゃない。
それは、あなたが「コード番長(Champion)」として、チームを救うヒーローになれる、最高の「チャンス」です。
僕のこの「グローバルコードプレイブック」の話が、あなたの「人生術」として、何か一つでもヒントになれば、こんなに嬉しいことはありません。
最後まで読んでくれて、本当にありがとう!
またどこかの国の、どこかのコードベースでお会いしましょう!

コメント