AIはコードを書ける。では、ソフトウェアエンジニアは何をするのか
第1回の今回は、AIが書いたコードがモバイル開発の現場でなぜ詰まるのかを題材に、エンジニアに求められる「コードの外側を見て判断する力」について解説します。
6:30
はじめに
家にパソコンがなかったので、ノートにコードを書いて、放課後にパソコン室でBASICをひたすら入力して、エラーになって、家に帰ってまたノートでゼロからコードを書き直す。そんな、世間一般的にはだいぶ変な中学生でした。
今は、ごく普通の中間管理職のソフトウェアエンジニアです。
今回、「Web記事を連載しませんか」というお話をいただきました。せっかくなので、AI時代のエンジニア論のようなものを書いてみようと思います。ただし、「これからのエンジニアはこうあるべきだ」と断言できるほど、きれいな答えを持っているわけではありません。
20年以上、Webやモバイル、少しだけ地図のエンジニアをやってきた人間が、AI時代にこれからどう生き抜いていくのか。ノラリクラリと生きてきたエンジニアとして、技術的なことも踏まえながら、AIとどう付き合うのかを書いてみようと思います。
この連載では、主にモバイルアプリ開発を題材にします。ただし、そこで起きる落とし穴の多くは、Webアプリやバックエンドの開発にも通じる話です。
AIはすでに仕事の相棒になった
多くのエンジニアの皆さんが、すでに何らかのAIツールを使っていますよね。コーディング、エラーの原因調査、テストの作成、リファクタリング案の提案、知らないライブラリの使い方を説明してもらう。 私も今では、AIを仕事のパートナーとして使っています。
最初に生成AIを触り始めたころは、正直なところ、そこまで信頼していませんでした。しかし、モデルが進化するにつれて、できることは確実に増えていきました。簡単なサンプルコードを書く程度ではなく、既存コードを読んで方針を提案し、修正案を出し、時にはこちらが思いつかなかった実装方法まで提示してくれるようになりました。
AIはコードを書けます。では、ソフトウェアエンジニアは何をするのでしょうか。 私は、その答えの1つは「判断すること」だと思っています。
AIへの指示には差が出る
私の周囲にいるAIを使っている人たちを見ていると、出てくる結果にはかなり差があるようです。 もちろん、使っているツールやモデルの違いもあります。賢いモデルが出るたびに、世間では「すごい、こんなものまで作れるようになった」とお祭り騒ぎになります。それ自体は本当にすごいことです。
ただ、私が見ている範囲では、モデルの違い以上に大きいのは「AIに何をどう伝えているか」です。 AIを早くから使ってきた人ほど、かなり細かく前提を渡す傾向があるように感じます。実装してほしい内容だけではなく、背景、制約、既存コードとの関係、避けたい設計、確認してほしい観点まで伝えます。
一方で、使い始めたばかりの人ほど、「これを作って」「このエラーを直して」「いい感じにして」と、比較的短く指示を出す傾向があるようです。もちろん、それでも最近のAIはそれなりに応えてくれます。むしろ、その曖昧さをある程度補ってくれるところに、現在のAIのすごさがあります。
ただし、曖昧な指示から出てきた成果物は、やはり曖昧な前提の上に立っています。
例えば、「一覧画面を作って」と頼めば、一覧画面は作ってくれるでしょう。しかし、その一覧は何件のデータを扱うのか、通信はいつ行うのか。失敗したらどうするのか、画面を閉じた後にレスポンスが返ってきたらどうなるのか、キャッシュは必要なのか、古い端末でも快適に動くのか。これらは考慮されているでしょうか。
こうした前提を渡さなければ、AIは“ 一般的にそれらしい実装”を返します。 それは、サンプルとしては動くかもしれません。しかし、プロダクトとして成立するとは限りません。
「郵便局を探すアプリ」を作るとしたら
例えば、現場でよくありそうな、こんな依頼を想像してみてください。
「郵便局を探すアプリを作ってほしい」
「顧客を管理するアプリに地図機能をつけてほしい」でも良いのですが、数のボリュームがちょうど良いので、とりあえず郵便局としましょう。
一見すると、そこまで難しくなさそうに聞こえるかもしれません。地図を表示して、郵便局の位置にピン、つまりMarkerを立てる。AIに頼めば、地図SDKを使ったサンプルコードや、Markerを表示する処理くらいはすぐに出してくれそうです。
しかし、ここに次のような条件が追加されることがよくあります。
- サーバーは使わず、オフラインでも表示したい
- 日本全国の郵便局をすべて対象にしたい
実際、車で移動することの多い営業の方で、日本全国に顧客を持つような業態の企業であれば、このようなことはありえます。「地図上で自分が回りやすい営業ルートを考えたい」「他の営業担当とバッティングしないように、最低限の情報は共有したい」「電波の入りにくい地域ではオフラインでも地図を表示したい」などです。
このとき、AIに素直にコードを書かせると、全データを読み込み、for文などのループ処理でMarkerを一気に作成し、地図上に表示するような実装が出てくるかもしれません。 コードとしては自然です。文法的にも間違っていません。実際、500件程度のデータであれば、その実装でも動くでしょう。
日本全国の郵便局は、およそ24,000箇所あります。これならどうでしょうか。多くの場合、メモリ使用量や描画負荷が大きくなり、操作が重くなったり、最悪の場合は「メモリ不足(OOM: Out Of Memory)」でアプリがクラッシュしてしまうでしょう。
社内ツールのように用途が限定されていて、扱うデータが500件未満だと分かっているなら、for文などのループ処理でMarkerを作成する実装も十分に現実的な判断です。しかし、製品として提供するのであれば、将来的に扱うデータ量が増える可能性や、端末性能のばらつきを考慮しなければなりません。
ここがまさに、AI時代のモバイル開発で起きやすい落とし穴です。
問題は「AIがコードを書けないこと」ではありません。AIはコードを書けます。問題は、そのコードが実際の端末上で快適に動くための制約を、AIが自動では十分に考慮できないことです。
MapView(mapViewState) {
for poi of postOffices {
Marker({
position: poi.latLng,
onClick: { clicked_poi ->
Print(`clicked : ${clicked_poi.name}`)
},
})
}
} 概念的なコードスニペット。 postOfficesの件数が多い場合、描画負荷やメモリ使用量が大きくなるため、 レビューで見落とすとUXの低下やOOM(メモリ不足)につながります。
「動くコード」と「快適に動く」は違う
24,000件のMarkerを一度に作るというのは、地図SDK内部の実装にもよりますが、24,000個の描画オブジェクトを同時に管理するようなものです。それはコードとしては書けますが、アプリとして成立するとは限りません。
モバイルアプリでは、端末性能やOSの状態、バッテリー、通信環境といった制約がユーザー体験に直接影響します。特にモバイルアプリでは、わずかな反応の遅れがUXに直結します。画面をスクロールしたとき、地図を動かしたとき、ボタンを押したとき。操作に対する反応が一瞬でも遅れると、ユーザーは「このアプリは重い」と感じます。つまり、本当に考えるべきなのは「Markerを表示するコードをどう書くか」だけではないのです。
データを読み込むタイミングはいつか。データ形式はどうするのか。属性によるカテゴライズや条件検索の有無。表示範囲外のデータをどう間引くのか。一度に表示する件数に上限を設けるのか。ズームレベルによって表示内容をどう変えるのか。重い処理をメインスレッド、あるいはUIスレッドで実行していないか。
AIに「地図上に郵便局を表示して」とだけ伝えると、AIはその言葉通りにコードを書こうとします。 しかし、モバイルアプリとして快適に動かすためには、こうした前提条件を人間が整理し、AIに渡す必要があります。あるいは、AIが出してきたコードを人間がレビューし、設計を補正する必要があります。
ここで必要なのは、単なるプロンプトのテクニックではありません。 仕様、データ量、端末性能、OSの挙動、ライブラリやSDKの癖、ユーザーの使い方、運用中に起きる問題。こうした「コードの外側」を見る力です。
丸2つでフクロウは描けるか
以前、元Googleのエンジニアの方から、テックリードの役割について話を聞いたことがあります。そのとき印象に残っているのが、「How to draw an owl」という有名なミームを使った説明でした。
最初に丸を2つ描く。次のステップで、いきなり立派なフクロウが完成している。途中の一番難しい工程が全部飛ばされている、というネタです。
この話は、AIへの指示にもよく似ています。
AIに対して、詳細なフクロウを描くように指示できれば、かなり高い確率で期待に近いものが出てきます。しかし、丸を2つだけ描いて「あとよろしく」と渡したとき、期待通りのフクロウになるかどうかは分かりません。
最近のAIはかなり賢いので、丸からフクロウを想像してくれる場面も増えています。それでも、そのフクロウが本当に自分たちのプロダクトに必要なフクロウなのかは、人間が判断しなければなりません。
ここで重要なのは、AIが賢いかどうかだけではありません。人間が、どこまで前提を整理できているかです。
AI時代だからこそ
基礎知識と経験に価値がある
AIが一般化すれば、多くの人がAIを使ってソフトウェアを作れるようになるでしょう。すでに、専門的な教育を受けていない人でも、AIに相談しながら簡単なアプリや業務ツールを作れるようになっています。
では、AIを使えること自体に、ソフトウェアエンジニアとしての価値は残るのでしょうか。私の持論を書かせてもらうと、「AIを使えるだけでは価値になりにくくなる」と思っています。価値になるのは「AIに何を任せ」「何を疑い」「どこを人間が判断するか」を決められることです。
そのためには、基礎知識が必要です。アルゴリズムやデータ構造は、日々の実務で毎日使うわけではないかもしれません。QuickSortを手で実装する機会はそれほど多くないでしょう。計算量を厳密に議論する場面も、業務によっては限られるかもしれません。
それでも、知っているかどうかで、気づける問題は変わります。この処理はデータが増えたら遅くなるのではないか。このループは本当に必要なのか。この状態管理は破綻しないか。この非同期処理は画面のライフサイクルと合っているか。このキャッシュはいつ破棄されるのか。この設計は半年後に機能追加できるのか。
AIが生成したコードは、最初は動いているように見えても、あとから修正しづらかったり、機能追加のたびに壊れたりすることがあります。1ファイルが数千行ある。複雑な条件式が何段にも入れ子になっている。アーキテクチャがない。テストもない。最初は動いていたけれど、少し直そうとすると、どこを触ればよいのか分からない。 想像するだけで、うんざりしますね。
「それもAIに直してもらえばいいじゃないか」と言えば、そうなのかもしれません。実際、AIはリファクタリングにも役立ちます。しかし、最終的にそのコードをリリースするのは人間です。バグがあっても、セキュリティホールがあっても、ユーザーに迷惑がかかっても、責任を取るのは人間です。
だからこそ、今動くかどうかだけではなく、半年後も直せるのか、運用できるのか、チームで扱い続けられるのかを判断する力が必要です。
AIは答えを出してくれます。しかし、問いを立てるのは人間です。 そして、その問いの質を支えているのが、基礎知識と、現場で痛い目を見てきた経験なのだと思います。
この連載で扱うこと
この連載では、AIが生成したコードが、モバイル開発の現場でなぜ詰まるのか、どうすれば落とし穴を回避できるのかを考えていきます。
モバイルアプリ開発は端末差、OSのバージョン、メモリ、通信環境、ライフサイクル、非同期処理、UIの状態管理など、考慮すべきことが多い領域です。最近はフレームワークが多くのことをうまく隠してくれます。Jetpack ComposeやSwiftUIのような宣言的UIも普及し、以前よりも書きやすくなりました。
しかし、「書きやすくなったこと」と、「理解しなくてよくなったこと」は違います。
なぜそのUIは再描画されるのか。なぜその非同期処理はキャンセルされるべきなのか。なぜ検索入力のたびにAPIを呼ぶと問題になるのか。なぜAIが生成したコードをそのまま積み上げると、あとで変更しにくくなるのか。こうした問いを、モバイルアプリ開発を題材にしながら考えていきたいと思います。
具体的には、次のようなテーマを扱う予定です。
- 非同期処理の落とし穴
async/await、Taskのキャンセル、画面破棄後にレスポンスが返ってくる問題 - UI再描画の落とし穴
SwiftUIやJetpack Composeで状態管理を誤ると何が起きるのか - APIリクエストの落とし穴
debounce、キャッシュ、レート制限とどう向き合うのか - アーキテクチャの落とし穴
AIが生成したコードを積み上げた結果、修正できなくなる構造の話
どれも、AIにコードを書かせるだけでは見落としやすい、現場のリアルなテーマです。
AIという強力な相棒が増えた今、エンジニアの仕事は、すべてのコードを自分の手で書くことから、何を作るべきかを整理し、どこを疑い、どう運用し、どう改善していくかを判断することへ、少しずつ重心が移っているのかもしれません。
では、ソフトウェアエンジニアは何をするのか。 私は「コードの外側を見て判断する」ことだと考えています。
AIは答えを出してくれます。実装も速くなりました。だからこそ、こちらが問いを立てる力を失うと、いつの間にかAIの出したものに[YES]を押すだけになってしまいます。
AIを使わない、という話ではありません。ただし、AIに使われないようにする。そのためには、手を動かし、自分で考え、失敗しながら「これは怪しい」と感じられる経験を積む必要があります。
AIに任せるところは任せる。でも、考えることまでは手放さない。
この連載では、そのために必要な判断の勘どころを、モバイル開発の落とし穴を題材にしながら、1つずつ考えていきます。
おわりに
次回は、モバイル開発で特に事故が起きやすい「非同期処理」について、具体的に掘り下げていきます。
この記事をシェアしてください
