海外C#エンジニアがガチで語る「AIに仕事させる技術」と「海外で生き抜く技術」の意外な共通点

AIと俺たち、そして「プロンプト」っていう新しい武器の話

どうも!はじめまして。海外(ヨーロッパのとある国)で、もうかれこれ数年、ITエンジニアやってます。メインの獲物はC#とWPF。

「え、今どきWPF?」って思った人、いるでしょ?(笑)

わかる。日本だとWeb系全盛期だし、デスクトップアプリっていうと「レガシー」なイメージあるかもだけど、こっちだとFA(ファクトリーオートメーション)とか、医療機器の制御ソフトとか、金融系のトレーディングツールとか、ミッションクリティカルな領域でまだまだ現役バリバリなんですよ、これが。むしろ「堅牢性」と「リッチな表現力」が求められる現場では、「やっぱWPFだよね」ってなるシーン、結構多いんです。C#の型安全最高。MVVMパターンでガチガチに設計して、XAMLでUI組んでいくのは、なんかこう「建築」してる感あって、俺は結構好きで。

で、そんな俺が、ここ1〜2年、現場で肌身に突き刺さるレベルで感じてる変化があります。

もう、言わなくてもわかると思うけど、AIの波です。

俺の隣の席に座ってるインド人のシニアエンジニアなんか、もうChatGPTが相棒。朝のスタンドアップ(朝会)で「昨日詰まってた件どうなった?」って聞かれたら、「ChatGPT先生に聞いて、こういう設計アプローチ見つけたから、今日実装トライしてみるわ」とか平気で言う。

Visual Studioに統合されたGitHub Copilotもヤバい。コメントで「// ユーザー情報をDBから非同期で取得して、ViewModelにバインドするメソッド書いて」とか日本語(!)で雑に書いても、public async Task LoadUserDataAsync() みたいなメソッドを、それっぽい try-catch とか CancellationToken まで考慮して一瞬で吐き出してくる。

最初は「うわ、便利すぎだろ。コピペ元のStack Overflow探す手間省けたわ」くらいに思ってたんですよ。

でも、そのうち「あれ……? これ、俺の仕事じゃね?」ってゾッとする瞬間が増えてきた。

特に、若手の子とか、これからエンジニア目指そうって人は不安だと思う。「プログラミング覚える意味、あんの?」って。

俺も正直、焦りました。「やっべ、俺、このままだと英語もAIも中途半端な『WPFおじさん』として終わるんじゃね?」って。せっかく海外まで来て、設計開発(Design and Development)っていう上流工程やってるプライドが、音を立てて崩れそうになった。

でも、ある時気づいたんです。

AIが吐き出すコードって、確かに「それっぽい」し「動く」んだけど、「最適」じゃないことが圧倒的に多い。

特に俺たちが扱ってるような、複雑なドメイン知識が必要な業務アプリとか、WPFの(ちょっとレガシーな部分も含む)DataBindingの癖とか、async/await が絡み合った時のスレッドセーフティとか、そういう「現場の泥臭い事情」を汲んだコードは、AIはまだ書けない。

なぜか?

俺たちの「指示」がヘボいからです。

雑な指示(プロンプト)からは、雑なコードしか生まれない。

これって、考えてみりゃ当たり前で。

新人の子に「なんかいい感じにユーザー管理機能作っといて」って指示したら、とんでもないものが出来上がるじゃないですか。それと全く同じ。

でね、最近、とある技術記事(英語のテックブログだったかな)で「Foundational Principles of Advanced Prompting(高度なプロンプティングの基本原則)」っていう考え方を知って、俺、マジで膝を打ちました。

その記事には、良いプロンプト(AIへの指示)に必要な要素は、主にこれだって書いてあった。

  • Clarity(明確さ):曖昧さをなくし、具体的に。
  • Context(文脈):背景情報、前提知識を与える。
  • Constraints(制約):やってはいけないこと、守るべきルールを指定する。
  • Desired Output Format(望ましい出力形式):JSONで、とか、箇条書きで、とか。

これ見た瞬間、俺、デジャヴに襲われたんですよ。

「……あれ? これ、俺が毎日C#でやってることじゃん」って。

マジで考えてみてほしい。

俺たちC#エンジニアって、本質的には「コンピューター(コンパイラ)っていう、クソ真面目だけど融通の効かないヤツ」に対して、**「超・明確に、文脈を与え、制約を課す」**プロフェッショナルじゃないですか?

例えば、C#でメソッドのシグネチャ(定義)を書くとき。

public static async Task<List<User>> GetUsersAsync(int departmentId, CancellationToken token)

これ、最強の「プロンプト」だと思いません?

  • public(明確さ):誰でも呼んでいいよ。
  • static(明確さ):インスタンスなくても呼べるよ。
  • async Task<List<User>>(明確さ&出力形式):非同期で、最終的に User のリストを返すよ。Taskっていう「引換券」を先に渡すよ。
  • GetUsersAsync(明確さ):メソッド名はこれね。Asyncもつけとくよ(お作法)。
  • int departmentId(文脈):departmentId っていう「整数」を文脈として渡すから、これ使ってね。
  • CancellationToken token(制約):token を渡すから、もしキャンセル要求が来たら、処理中断してね(制約)。

俺たち、毎日こんなレベルの「明確な指示」を書いてる。

WPFのXAMLだってそう。

<TextBlock Text=”{Binding UserName}” Style=”{StaticResource TitleStyle}” />

これは「UserNameっていう文脈(DataContext 内のプロパティ)に繋げ(Binding)」「TitleStyleっていう制約(スタイル)に従って」「テキストを表示しろ」っていう、超具体的な指示書です。

「Clarity」「Context」「Constraints」。

これって、C#の「型システム(string? みたいなNull許容参照型とか)」「インターフェース(interface)」「ジェネリクスの型制約(where T : class)」そのもの。俺たちがバグを減らして、堅牢なシステムを設計(Design)するために、ずっと磨いてきた技術そのものなんですよ。

そして、この気づきは、もう一つの、もっとデカい真実に繋がりました。

この**「明確さ・文脈・制約を意識して伝える技術」**って、

「非ネイティブが海外でエンジニアとして生き抜くための、最強のコミュニケーション術」

と、全く同じだったんです。

俺、こっち来て最初の頃、めっちゃ失敗したんですよ。

日本人的な「たぶん大丈夫だと思います」とか「(相手の意図を)察する」文化で仕事しようとして。

良かれと思って、仕様書に書いてない「ちょっとした改善」を実装してプルリク投げたら、レビューで「Why?(なんで?)」の嵐。

「いや、こっちのがユーザーフレンドリー(WPFのUI)かなって…」って言ったら、「勝手なことすんな。仕様(Constraints)と違う。他の機能との整合性(Context)はどうなってんだ」って、めちゃくちゃ怒られたり。

逆に、WPFのパフォーマンスチューニングで、どうしても仕様変更が必要になった時。

俺、つたない英語で、こうプレゼンしたんです。

  1. Context(文脈):「今、この画面(具体的に画面キャプチャ見せて)で、1万件のデータを読み込むと、UIが5秒フリーズする。これが現状の問題(文脈)だ」
  2. Clarity(明確さ):「原因は、UIスレッドで重い処理をしてるからだ。非同期処理とUIの仮想化(Virtualization)が必要だ」
  3. Constraints(制約):「ただし、今のアーキテクチャだと、仮想化を実装するにはXX(ライブラリ)の変更が必要で、工数が3週間かかる。もし『フリーズしてもいいから今週中にリリース』が絶対の制約(Constraint)なら、俺は対応できない」
  4. Proposal(提案=望ましい出力):「そこで提案。初期読み込みは100件にして、『もっと見る』ボタンで追加読み込み(遅延ローディング)する仕様に変えないか? これなら工数は3日だ」

そしたら、マネージャーもデザイナーも「OK、Taro(俺の名前)の言ってること、超クリアだ。その提案(Clarity)でいこう。ただし、ボタンのデザイン(Constraints)はこっちで決める」って、一発で通ったんです。

この時、ハッとした。

AIにうまく指示が出せないヤツは、人間(特に文化も言語も違う海外の同僚)にも、うまく指示が出せないし、意図も伝えられない。

逆に言えば、俺たちC#エンジニアが設計と開発(Design and Development)で培ってきた「いかに曖昧さを排除し、文脈を共有し、制約を定義するか」っていう思考法こそが、AIを最強の部下にする技術であり、海外で信頼を勝ち取るコミュニケーション技術であり、もっと言えば「人生をうまく進めるための交渉術」そのものなんじゃないか、と。

「プログラミング言語」っていうのは、突き詰めれば「コミュニケーション言語」の一つ。

俺たちは、AIやコンピューターと「対話」するための、超厳密な言語をすでに知ってる。

だったら、その「対話術」を、AI相手にも、人間相手にも応用すりゃいいじゃん。

…と、これが今回俺が一番伝えたかった「気づき」です。

これが「起」。

ちょっと語りすぎたけど(笑)、ここが全ての土台。

続く「承」では、この「Clarity(明確さ)」「Context(文脈)」「Constraints(制約)」っていう3つの原則を、俺がやらかしたC#のコードと、海外生活でのリアルな失敗談・成功談を交えながら、もっとエグいレベルで深掘りしていきます。

読んだら「あー、それな!」ってなるか、「そんな考え方あったか!」ってなること間違いなし。

AI時代に「使われる」側じゃなくて「使いこなす」側のエンジニアになりたい人は、ぜひついてきてください。

C#の「型」と英語の「Why?」、AIを動かす「文脈」の正体

「起」で、俺たちC#エンジニアは「超・明確に、文脈を与え、制約を課す」プロだって話をしたよね。

これ、マジでAI時代とグローバル社会の「最強の武器」になる。逆に、これができないと、AIにはおかしなコードを吐かせ、海外の同僚からは「コイツ、何が言いたいの?」って思われて、詰む。

俺がやらかした失敗談と、そこから学んだ「処方箋」を、3つの原則に分けてガチ語りさせてほしい。

1. Clarity (明確さ):「Null」と「I think」の恐怖

まず「明確さ」。これがないと、C#ではバグが生まれ、人間関係では誤解が生まれる。

【C#のやらかし】: NullReferenceException と「暗黙の期待」

昔、俺がまだこっち(海外)に来たばかりの頃、書いたコードがある。

C#

// やらかしコード(明確さゼロ)
public User GetUser(int userId)
{
// DBから探す処理...
if (user == null)
{
return null; // 見つからなかったら null を返す
}
return user;
}

// 呼び出し側
var user = GetUser(123);
Console.WriteLine(user.Name); // ←ここでクラッシュ! (NullReferenceException)

これ、最悪。

何が最悪かって、「GetUserっていうメソッドは、Userを必ず返す」ってシグネチャ(定義)で言ってるのに、平気で null を返す「嘘」をついてるところ。

呼び出し側は「Userが返ってくる」って信じてるから、当然のように user.Name にアクセスして、見事にコケる。

「いや、nullチェックするのが常識でしょ」って思う? 甘い。

大規模なシステム、特に俺がやってるWPFみたいな複雑なUIが絡むと、どこで null が渡ってきたかなんて追うのは地獄。

これ、AIへの指示と全く同じ。

AIに「この機能のUIデザイン案、作って」って雑に頼むのは、「GetUser呼んどいて」って言うのと同じ。

AIは「はいよ!」って、なんかそれっぽいデザイン(nullかもしれない何か)を返してくる。でも、こっちが「モダンで、フラットデザインで、うちの会社のブランドカラー(#FF6600)をアクセントに使って」っていう「明確な期待」を伝えてないと、出てきたものが使い物になるわけがない。

【処方箋 → C#とコミュニケーション】

じゃあどうすりゃいいか。C#が答えを持ってる。

C#

// 改善コード(明確さMAX)
// 1. Null許容参照型で「nullかもよ」と明示する
public User? GetUserById(int userId)
{
// ...
return user; // nullかもしれない
}

// 2. Tryパターンで「成功/失敗」を明確に分ける
public bool TryGetUser(int userId, out User? user)
{
// ...
if (found)
{
user = foundUser;
return true; // 明確に「成功」
}
user = null;
return false; // 明確に「失敗」
}

C# 8.0から入った「Null許容参照型(User?)」、あれは革命だよね。

コンパイラが「おい、お前、GetUserByIdが null 返すかもしれねーぞ。nullチェックしろよ!」って強制的に警告してくれる。

TryGetUserパターンも最強。戻り値が bool(真偽)だから、「成功したか、失敗したか」を呼び出し側が絶対に意識せざるを得ない。

これ、海外でのコミュニケーション術に直結する。

俺、昔、仕様レビューで「This specification is a bit difficult.(この仕様、ちょっと難しいですね)」って言ったことがある。

日本で言う「難しい」は、「無理です」「やめたほうがいい」「工数かかりますよ」っていう**「No」のニュアンス**を含むじゃない?

でも、こっちのエンジニア(ドイツ人だった)に伝わったのは、「OK, it’s challenging, but possible.(なるほど、挑戦的だが、可能だ)」だった。

結果、プロジェクトはそのまま進んで、後でデスマーチになった。俺の「明確さ」がゼロだったから。

今は、こう言う。

「No, this is not difficult, this is high-risk.(いや、これは『難しい』んじゃない、『リスクが高い』んだ)」

「Why?(なぜ?)」と聞かれたら、

「Because this breaks our MVVM pattern (Constraint), and requires 3 weeks of testing (Context).(なぜなら、これはMVVMパターンを壊すし、3週間のテストが必要になるからだ)」

「My proposal is to use pattern B instead. This is low-risk and takes 3 days.(代替案としてBパターンを提案する。低リスクで3日で終わる)」

bool で返すのと同じ。「Yes/No」を明確にし、その「理由(out User)」を添える。

AIにも「このデザインはダメだ」じゃなくて、「このデザインは、指定したブランドカラー(#FF6600)を使ってないからダメだ(明確な理由)。修正して」って言う。

「明確さ」は、バグと炎上を防ぐ第一歩。


2. Context (文脈):「マジックナンバー」と「Why?」の嵐

次に「文脈」。これが無いコードは読めないし、これがない発言は理解されない。

【C#のやらかし】: if (status == 3) の地獄

俺がこっちでメンテを引き継いだレガシーなWPFアプリが、マジで地獄だった。

コードの至る所に、こういうのが散らばってる。

C#

// やらかしコード(文脈ゼロ)
private void UpdateButtonVisibility(int userStatus)
{
if (userStatus == 3 || userStatus == 5)
{
// 承認ボタンを表示する
this.ApproveButton.Visibility = Visibility.Visible;
}
else
{
this.ApproveButton.Visibility = Visibility.Collapsed;
}
}

「3って何? 5って何?」

userStatus が「3」か「5」のときに承認ボタンが表示されるらしい。

なんで?

この「3」と「5」を、俺たちは「マジックナンバー」と呼ぶ。

「文脈」が完全に欠落してる。

DBの仕様書を漁り、古のドキュメントを読み解き、やっと「3 = ‘PendingApproval’」「5 = ‘Resubmitted’」だと突き止めるのに、半日かかった。クソすぎる。

これ、AIへの指示と全く同じ。

AIに「ユーザーが3か5だったら、承認ボタンを出すWPFのXAML書いて」って言っても、AIは「はいよ!」って上のコードを生成するだけ。

AIは「3」が「承認待ち」だなんて知らない。文脈を与えてないから。

【処方箋 → C#とコミュニケーション】

C#エンジニアなら、1秒でわかるよね。

そう、「enum(列挙型)」を使え、と。

C#

// 改善コード(文脈MAX)
public enum UserStatus
{
New = 1,
Active = 2,
PendingApproval = 3, // 3は「承認待ち」
Rejected = 4,
Resubmitted = 5, // 5は「再提出」
}

private void UpdateButtonVisibility(UserStatus status)
{
// 文脈が明確!
if (status == UserStatus.PendingApproval || status == UserStatus.Resubmitted)
{
this.ApproveButton.Visibility = Visibility.Visible;
}
// ...
}

int じゃなくて UserStatus っていう「型」で渡す。

これだけで、「3」が「PendingApproval(承認待ち)」っていう**「文脈」**がコードに刻み込まれる。

WPFの DataContext もそう。View(XAML)に対して「この画面の文脈(データ)は、このViewModelですよ」って教えてあげるのが DataContext。文脈がなきゃBindingもクソもない。

海外でのコミュニケーションでも、この「文脈(Why?)」が死ぬほど大事。

日本だと「(空気を読んで)まぁ、こういう事情があるんだろう」って察してくれるけど、こっちは(特にエンジニアは)ロジックの塊。

文脈がない発言は、マジでスルーされるか、「Why?」の嵐に見舞われる。

俺がやらかしたのは、あるミーティング。

いきなり「パフォーマンス改善のために、ここのデータ取得を Task.WhenAll で並列化すべきです」って**「How(どうやるか)」**から話し始めた。

シーン…ってなった後、シニアアーキテクト(フランス人)が一言。

「Taro, Why?(タロー、なんで?)」

「え、いや、速くなるから…」

「Why do we need it now?(今、それがなんで必要なの?)」

「……」

俺は「今、ユーザーから『この画面が遅い』ってクレームが来てる(文脈)」をすっ飛ばして、「解決策(How)」だけを話してた。

彼らにとっては、if (status == 3) って言われてるのと同じ。「3(並列化)? なんで?」ってなる。

今は、絶対に「Why(文脈)」から話す。

「今、P1(最優先)のバグとして『XX画面が5秒フリーズする』というチケットが起票されている(文脈)。原因は、3つのAPIを直列で呼んでいるためだ(文脈)。そこで、これを Task.WhenAll で並列化し、レスポンスを1.5秒に短縮したい(提案/How)」

こう言えば、全員が「OK, got it.(わかった)」ってなる。

AIにプロンプトを投げる時も同じ。

「C#のコード書いて」じゃダメ。

「背景(Context): 私は今、WPFアプリのパフォーマンスチューニングをしている。問題: ListView に1万件のデータをバインドするとUIがフリーズする。解決したいこと: UIフリーズを防ぎたい。アイデア: UI仮想化と非同期データロードを使いたい。指示: この文脈に沿って、ObservableCollection を使った非同期ロードとUI仮想化を有効にした ListView のサンプルコード(XAMLとC#のViewModel)を書いて」

ここまで「文脈」を与えれば、AIは神コードを返してくる。


3. Constraints (制約):「async void」と「スコープ」の罠

最後は「制約」。何をやらないか、何を守るべきか。

これが一番、シニアエンジニアとジュニアを分けるポイントかもしれない。

【C#のやらかし】: async void の地雷

C#の非同期処理(async/await)、WPFでも必須だよね。UIをフリーズさせないために。

で、初心者がやりがちなのが「async void」。

C#

// やらかしコード(制約ゼロ)
// ボタンクリックイベントハンドラ
private async void OnLoadDataClicked(object sender, RoutedEventArgs e)
{
// このメソッドは「await(待機)」できない!
// 呼び出し元は、終わったかどうかわからない。
// 例外が起きたら、アプリごとクラッシュする!
await LoadDataFromServerAsync();
}

async void、これ「制約なき力」みたいなもんで、超危険。

このメソッドは Task を返さないから、呼び出し元が「await」できない。つまり、処理が終わるのを待てない。

さらに最悪なのは、LoadDataFromServerAsync() の中で例外が起きたら、try-catch で囲んでない限り、アプリ全体を巻き込んでクラッシュする。(WPFだと Application.DispatcherUnhandledException で一応キャッチできるけど、原則ヤバい)

AIへの指示でも同じ。

「ブログ記事書いて」って「制約ゼロ」で頼むと、AIは平気で1万文字の超大作(async void)を返してきたり、架空の人物や事実を捏造(例外クラッシュ)したりする。

【処方箋 → C#とコミュニケーション】

C#の答えは「async Task を使え」。

C#

// 改善コード(制約あり)
private async Task LoadDataAsync()
{
try
{
// ... 重い処理 ...
}
catch (Exception ex)
{
// 例外をちゃんと処理する
}
}

// 呼び出し側(イベントハンドラは仕方ないとして)
private async void OnLoadDataClicked(object sender, RoutedEventArgs e)
{
await LoadDataAsync(); // Taskを返すメソッドを呼ぶ
}

Task を返すことで、「俺は非同期で、いつか終わる『作業』だ」と宣言する。呼び出し元はそれを await する「義務」と「権利」を得る。例外も Task にカプセル化されるから、安全に try-catch できる。

C#の interface(インターフェース)も最強の「制約」だよね。「このメソッドを絶対に実装しろ」っていう「契約(Constraint)」。

ジェネリクスの where T : class(Tは参照型じゃないとダメ)とかも全部「制約」。

俺たちC#エンジニアは、日々「制約」の中で設計してる。

これを、海外での仕事にそのままスライドさせる。

俺がマジで学んだのは「スコープ(担当範囲)の制約」を最初に決めること。

やらかしたのは、PMから「この画面に、エクスポート機能つけといて」って軽く言われた時。

俺「OK!(async void)」

で、実装し始めたら、「あれ、CSV? Excel?」「全件? 表示されてる分だけ?」「権限管理は?」…キリがない。

俺が良かれと思って「CSVで全件」を実装したら、PMが「いや、Excelで、権限ある人だけって言ったじゃん!(言ってない)」ってキレられた。

今は、絶対に「制約」から確認する。

「OK。その機能、やるよ。でも**Constraints(制約)**を決めさせてくれ」

「1. スコープ(範囲): 俺がやるのは『ボタンを押したらCSVがダウンロードされる』ところまで? それとも『権限管理』もスコープ内?」

「2. タイムライン: 期限はいつ? 来週のリリースが絶対(制約)なら、権限管理は無理だ」

「3. やらないこと(Not-Do): Excel対応は、今回はスコープ外(制約)でいい?」

こうやって「制約」を明確に握っておけば、後で「言った・言わない」の地獄が始まらない。

これは、コードの interface を決める設計会議と全く同じ。

AIにも「ブログ記事を書いて。制約:ターゲットは20代のITエンジニア。制約:文字数は1500文字以内。制約:専門用語は使わず、カジュアルな口調で。制約:架空の事例は使わないこと」

ここまで「制約」をかければ、AIは async Task のように、期待通りの「Task」を安全に完了してくれる。


…と、ここまでが「承」。

「明確さ」「文脈」「制約」が、いかにC#とAIと海外サバイバルに共通してるか、俺の恥ずかしい失敗と共に分かってもらえたかと思う。

でも、これだけだと「ふーん、わかった。じゃあ、明日からやればいいんでしょ?」って思うかもしれない。

甘い。

次の「転」で、この3原則を「知ってる」と「できる」の間に横たわる、深くて暗い「落とし穴」の話と、それを乗り越えた先にある「AIを使いこなす」エンジニアの、本当の価値について話そうと思う。

この3つを実践しようとしたヤツが、**必ずぶち当たる「壁」**があるんだ。

なぜ「わかってて」もできないのか?AIと海外が炙り出す「思考のコスト」という名の壁

「承」で、俺はC#の「Null許容型」とか「enum」とか「async Task」とか、海外での「Why?」とか「No」とか、偉そうに語ったよね。

「なるほど、明日から俺も『明確に』『文脈を』『制約を』意識してAIと人間に指示しよう!」

そう思った人もいるかもしれない。

でも、悪いけど、たぶん失敗する。

俺がそうだったから。

この3原則を実践しようとすると、必ず、とんでもなく分厚い「壁」にぶち当たる。

その壁の正体。

それは、**「思考のコスト」と「摩擦(コンフリクト)のコスト」**だ。

AIも、海外の同僚も、俺たちに「楽をさせてくれない」。

むしろ、俺たちの「思考の怠惰」を容赦無く炙り出してくる。

これが「転」。俺たちの最大の敵は、AIでも英語でもなく、**「めんどくさがって、思考停止したい自分」**なんだ。

1. 「明確さ」のコスト:「決断」から逃げるな

「明確に指示しよう!」って、言うのは簡単。

でも、「明確にする」ってのは、「曖昧さの余地をゼロにする」ってこと。

これ、C#で言えば「string」じゃなくて「string?」のどちらを選ぶか、「int」じゃなくて「uint」(マイナスを許容しない)を選ぶか、「決断」し続ける作業だ。

俺がWPFの設計でやらかしたのは、あるViewModelに public string StatusMessage { get; set; } っていう、まぁよくあるプロパティを定義した時。

AI(Copilot)に「このViewModelのテストコード書いて」って頼んだら、AIは StatusMessage = “Success” とか StatusMessage = “Error” みたいなテストを自動生成した。

でも、本番で入ってきたデータは StatusMessage = null で、それがXAMLのBindingで変な空白を生んで、UIが崩れた。

AIは悪くない。俺が悪い。

俺が「string?(nullを許容する)」と「明確に」定義しなかったから、AIは「string(nullじゃないはず)」と解釈した。

なぜ string にしたか?

「nullの時、UIでどう表示するのが『明確な』仕様か」を決めるのが、めんどくさかったからだ。

海外のコミュニケーションも同じ。

「承」で「No, this is high-risk.」って明確に言え、と書いた。

でも、これを言うの、めちゃくちゃ怖いんだよ。

だって「No」って言ったら、相手(マネージャーとか)は絶対に「Why?」って聞き返してくる。「じゃあ代替案(Proposal)は?」って詰めてくる。

それに答えるには、ロジックを完璧に組み立てないといけない。

それが怖いから、俺たちは「I think it’s a bit difficult…(ちょっと難しいかも…)」っていう**「曖昧さ(string)」に逃げる**。null(=無理かも)の可能性を隠して。

「明確さ」には、「決断する」という高い思考コストと、「対立するかもしれない」という摩擦コストが伴う。

AIへのプロンプトも同じ。「この機能のコード書いて」って雑に(曖昧に)投げた方が「楽」。

「こういう設計思想(MVVM)で、こういう制約(.NET 6)で、こういう例外処理(GlobalExceptionHandler)を前提に」なんて「明確な」プロンプトを書くのは、それ自体が**「設計書」を書くのと同じ**くらい、頭を使う。

2. 「文脈」のコスト:「当たり前」を言語化する地獄

次に「文脈」。if (status == 3) がダメで、enum UserStatus.PendingApproval を使えって話。

これ、「やるのがめんどくさい」の典型例。

マジックナンバー(3)を書くのは1秒。

enum を定義して、UserStatus.PendingApproval = 3, とか書いて、その enum ファイルを適切なフォルダに配置して、using でインポートして…ってやるのは、3分かかる。

たった3分。でも、プログラマーって、この3分をケチる生き物なんだよな。

「今は俺しか触らないコードだから」「俺は『3=承認待ち』って覚えてるから」

この「未来の自分」と「他人」に対する「文脈共有コスト」のケチりが、半年後にコードを地獄に変える。

海外の現場じゃ、これが毎日起きる。

こっちのエンジニアは、とにかく「Why?(なんで?)」を連発する。

俺が「このWPFのListView、仮想化(Virtualization)をオンにしましょう」って提案した時。

日本なら「お、パフォーマンスチューニングか。いいね(察し)」で終わる。

こっちのシニアエンジニア(オランダ人)は違った。

「Why?(なんで?) 今、問題起きてる?」

「いや、将来的にデータが1万件超えたらUIが固まる『可能性』があるから…(文脈)」

「’可能性’ のために、既存の安定したコード(制約)を変更するリスクを取るのか? その『1万件』の根拠(文脈)は?」

「……(うっ)」

俺は「WPFのListViewは大量データに弱い」という、自分の中の「当たり前(暗黙の文脈)」を説明するのをサボった。

AIに対しても同じ。

「WPFでMVVMのコード書いて」って頼む時、俺たちの頭の中には「Prism(フレームワーク)を使って」「DI(依存性注入)は DryIoc で」「ViewModelの基底クラスは BindableBase を継承して」みたいな**「暗黙の文脈」**が大量にある。

その「文脈」をAIに与えなければ、AIは素の(あるいは全然違う流派の)MVVMコードを吐き出す。それを見て「使えねーな、AI」って言うのは、あまりにも傲慢だ。

「文脈」を伝えるのは、**「自分の頭の中の『当たり前』を、全部『言語化』する」**っていう、地獄のようにめんどくさい作業。

このコストを払えるかどうかが、マジで分かれ目。

3. 「制約」のコスト:戦って「決め事」を作る勇気

最後が「制約」。async void じゃなくて async Task。スコープを決めろ、と。

これが、3つの中で最も高い「摩擦コスト」を要求される。

「制約」ってのは、「ルール」だ。そして「スコープ(やらないこと)」を決めること。

interface を定義するのは、まさに「制約」を作る作業。「このメソッド名で、この引数で、この戻り値を返すこと」を「契約(Contract)」として強制する。

これ、超・政治的な行為なんだよ。

俺がいたチームで、ある機能をC#で実装する時。

Aさん「Result オブジェクトを返すパターン(Result<T>)で統一しよう(制約の提案)」

Bさん「いや、普通に例外(Exception)を投げるべきだ(制約の提案)」

ここでバトルが起きる。

どっちが「正しい」かじゃない。どっちを「チームの制約として採用するか」の**「交渉」と「決断」**だ。

この議論、めんどくさい。正直、どっちでもいいから早くコード書きたい。

でも、ここで「まあ、個々で好きにやればいいじゃん(制約ゼロ)」と逃げたチームのコードは、async void だらけのアプリみたいに、必ず破綻する。

海外の現場は、この「制約の交渉」が日常茶飯事。

PM「この画面、今日中にリリースね(制約の提示)」

俺「いや、テスト(俺たちの開発プロセスの制約)がまだだ。リリースは明日になる」

PM「テストは後でいいから、とにかく出せ」

俺「No. 俺たちのチームの『制約(ルール)』は『テストカバレッジ80%以下のコードはMasterにマージしない』だ。この『制約』を破るなら、あなたが責任を持って(リスクの文脈)、シニアマネージャーの承認(明確さ)を取ってくれ」

ここまで戦う必要がある。

async void で「あ、はい、やります(クラッシュ覚悟)」って言うのが一番「楽」だけど、一番ダメ。

async Task で「Task(作業)は返す。でも、いつ終わるかは俺が決めるし、例外が出たらちゃんと伝える(awaitしてね)」って宣言するのが「制約」を守るエンジニアの仕事。


つまりだ。

AIに「明確な」プロンプトを書くのも、海外の同僚と「文脈を」すり合わせるのも、PMと「制約を」交渉するのも、全部**「クソめんどくさい思考コスト」と「ヒリヒリする摩擦コスト」**がかかる。

AIが代替する仕事は、この「コスト」を払うことから逃げた人間の仕事だ。

指示された「How(どう書くか)」だけを、思考停止でコードに落とし込む作業。そんなの、Copilotのほうが俺たちより100倍速い。

じゃあ、俺たち「設計開発」をやってるエンジニアの価値はどこにある?

それは、この「思考コスト」と「摩擦コスト」を、AIや他人に丸投げせず、自ら進んで引き受けることにある。

C#で interface を設計するように、「何を(Clarity)」「なぜ(Context)」「何をやらないか(Constraints)」を、血反吐を吐きながら「決める」こと。

その「決めた」最強のプロンプト(仕様書)を、AIに投げる。あるいは、人間の同僚に渡す。

これが、AI時代の「設計エンジニア」の仕事だ。

「起承転結」でいう「転」。

敵はAIじゃなかった。俺たちの「怠惰」と「恐怖」だった。

じゃあ、この「コストを払える筋肉」はどうやって鍛えればいいのか?

プロンプトの「Iterative Refinement(反復的な改善)」ってのは、AIにやるもんじゃない。自分自身にやるもんなんだ。

…という話が、最後の「結」だ。

君の「C#脳」は最強の武器だ。AIと世界を「設計」する人生術

「転」で、俺たちは「明確さ(Clarity)」「文脈(Context)」「制約(Constraints)」を実践するには、クソめんどくさい「思考コスト」と「摩擦コスト」がかかるって話をした。

じゃあ、そのコストを払い続ける「筋肉」はどうやって鍛えるんだ?

答えは、フックの2番目と3番目にあった。

「The art of iterative refinement(反復的改善のアート)」

「Leveraging multi-modal prompts(マルチモーダル・プロンプトの活用)」

これが、俺たちC#エンジニアがAI時代とグローバル社会を生き抜くための、具体的な「人生術」そのものだったんだ。

1. 「反復的改善」とは、AIではなく「自分」をデバッグすること

まず「Iterative Refinement(反復的改善)」。

これ、AIへのプロンプトを何度も書き直すことだ、って普通は思うよね。

違う。

AIがクソな回答を返してきたら、AIを責めるな。100%、お前のプロンプト(指示)がクソだったと反省しろ。

これが、AIを「部下」として使いこなすための鉄則だ。

  • AIが生成したC#コードがバグだらけ?→ お前の「制約(Constraints)」の指定が甘い。「.NETのバージョンは?」「使うべきライブラリは?」「例外処理のパターンは?」をサボったな。
  • AIが的外れなブログ記事を書いてきた?→ お前の「文脈(Context)」が足りない。「ターゲット読者は?」「記事の目的(Why)は?」「読後感は?」を言語化しなかったな。
  • AIが曖昧なデザイン案を出してきた?→ お前の「明確さ(Clarity)」がゼロ。「『いい感じ』じゃなくて『#FF6600を基調としたフラットデザイン』ってなぜ言わなかった?」

これ、俺たちが毎日やってる**「デバッグ」作業そのものじゃないか?

WPFアプリが NullReferenceException でクラッシュした時、俺たちは「WPFがクソだ」とは言わない(いや、たまに言うけど)。「あ、俺が if (viewModel.User != null) のチェックを忘れてたわ」って「自分」を修正する**。

「転」で話した「思考コスト」を払う筋肉は、**「AIや他人のせいにするのをやめ、自分の『指示(プロンプト)』を反復的に改善(デバッグ)し続ける」**という、このクソ地道な作業によってのみ鍛えられる。

これは、海外の同僚とのコミュニケーションでも全く同じ。

俺のつたない英語が伝わらない時、俺は「なんでこいつは理解しねえんだ(摩擦コストから逃亡)」と思うのをやめた。

「OK、今の俺の『プロンプト(英語)』はクソだった。どう『リファイン』すれば伝わる?」

と、自分をデバッグする。

「It’s difficult(難しい)」が伝わらないなら、

「It’s high-risk(高リスクだ)」とリファインする。

それでも伝わらないなら、次の「マルチモーダル」だ。

2. 「マルチモーダル」とは、「言葉」で殴るのをやめる技術

フックの最後、「integrating visual and numerical data(ビジュアルと数値データの統合)」。いわゆる「マルチモーダル」だ。

これ、AIに画像や数値を食わせる話だけじゃない。

**「言葉(Text)だけでコミュニケーションするのを諦める」**という、最強の「摩擦コスト削減ハック」だ。

俺の英語がクソだったとしても、「Why?」って詰められても、俺には「武器」がある。

「OK、言葉じゃ無理だ。ホワイトボード、借りるぞ」

俺は、WPFの画面遷移(Visual)と、C#のクラス図(Visual)を、汚い線で描く。

「This is ViewModel A (Context). Click this button (Clarity), and it sends Message X (Constraint). This is ViewModel B (Context). It receives Message X (Constraint). But the problem is…(でも問題は…)」

そうやって「絵(Visual)」で説明したら、さっきまで「Why?」しか言わなかったドイツ人もフランス人も、一発で「Ah… OK, I got your point!(あー、なるほど、言いたいことわかった!)」ってなる。

「この画面、なんか遅いんだよね(曖昧なText)」じゃなくて、

「この画面、プロファイラ(Visual/Numerical)で見たら、LoadUserDataメソッドで5000ms(Numerical)かかってる(Clarity)」

って言う。

これ、俺たちITエンジニアが日常的にやってる「マルチモーダル・コミュニケーション」だ。

言葉(日本語/英語/C#)は、しょせん「Textプロンプト」の一つでしかない。

Textがダメなら、Image(図、スクリーンショット、UML)を使え。

Imageがダメなら、Number(数値、メトリクス、工数)を使え。

これらを組み合わせることで、「文脈」は爆発的に伝わりやすくなり、「摩擦コスト」は劇的に下がる。

AIに対しても同じ。

「こういう雰囲気のUI作って」じゃなくて、参考サイトの「画像(Visual)」を食わせて、「この画像のレイアウト(Constraint)と、このカラーパレット(Context)を使って」と指示する。

これが「マルチモーダル・プロンプト」の神髄だ。

【結論】C#エンジニアよ、その「設計脳」を解放せよ

長々と語ってきたけど、結論はシンプルだ。

AI時代に生き残るための「高度なプロンプティング技術」とは、何か新しいスキルのことじゃなかった。

俺たちC#エンジニアが、堅牢なシステムを「設計(Design)」するために、日々WPFや.NETの奥深くで格闘しながら培ってきた「思考法」そのものだった。

  • string? で「Nullの可能性(Clarity)」を定義する思考。
  • enum で「マジックナンバーの背景(Context)」を定義する思考。
  • interface や async Task で「守るべき契約(Constraints)」を定義する思考。
  • デバッグで「自分の間違い(Bug)」を「反復的改善(Iterative Refinement)」する思考。
  • UMLやプロファイラで「ビジュアルや数値(Multi-modal)」を使って問題を特定する思考。

俺たちは、とっくに持ってたんだ。

この、**「曖昧さを殺し、文脈を与え、制約を定義し、反復的に改善する」**という、最強の「設計脳」を。

これからは、その「C#脳」を、コンピューター(コンパイラ)相手だけじゃなく、**AI(ChatGPT, Copilot)と、人間(海外の同僚)**に対しても、フルパワーで解放してやればいい。

「プロンプトエンジニアリング」なんて言葉にビビるな。

俺たちは、その「ネイティブスピーカー」だ。

海外で働くことも、AIを使いこなすことも、本質は同じ。「いかにして『意図』を正確に伝えるか」という「設計」の問題だ。

君がC#とWPFで培ってきたその「設計力」は、単なるプログラミング技術じゃない。

AIに「指示を出す」ための技術であり、文化の違う相手と「信頼を築く」ための技術であり、そして、曖昧なこの世界を「生き抜く」ための、最強の「人生術」だ。

コメント

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