よいコードを書くためには,設計の基本を守り,既存のコードを読むことが必要である – Java ChampionでハイパフォーマンスコンピューティングのスペシャリストであるMartin Thompson氏のことばだ。InfoQは,QCon London 2016で“Engineering You”と題した講演を終えた氏に,ソフトウェア産業が直面する課題は何か,プログラマがそれを克服して優れたソフトウェアエンジニアになるにはどうすればよいのか,などをインタビューした。
InfoQ: 講演の中であなたが引用した,1986年の,ソフトウェアエンジニアリングに関する最初のNATOカンファレンスの内容は,現在でも通用します。ソフトウェア産業がいまだ問題を解決できないのはなぜでしょう?
Martin Thompson: 1986年のNATOカンファレンスには,たくさんのテーマがありました。彼らはソフトウェア産業が危機的状況にあることに気付いていたのです。その一方で,成功を収めたプロジェクトがあることも分かっていましたから,その成功理由を見つけ出して,より広い範囲に適用できるようにしたいとも思っていました。私が考える成功理由は,ソフトウェア開発が反復的であること,実験と学習を重視する実践者がリードするものであること,小規模なチームに向いているものであることを認識し,それらを実現した点にあります。多くの点で彼らは,一般的な手法になる何十年も前にTDDやアジャイルを語っていた,ということです。
私たちの業界は大きく発展してきましたが,先にはまだ,長い道程があります。ソフトウェア開発の分野はまだ非常に若く,学ぶべきことはたくさんあります。ダイクストラ氏が“ラジカルノベルティ(radical novelty)”だと説明したように,まったく不適切なメタフォやアナロジを使うことで,私たちは自ら失敗の原因を作り出しているのです。ソフトウェア開発は,従来のアクティビティとはまったく違います。活動や制約の内容が,従来のアクティビティとは根本的に異なっているのです。生来の才能に恵まれた人や,努力で身に付けた人も一部にはいますが,ほとんどの人たちは苦労を積み重ねています。土木工学が現在の能力に到達するには何世紀も掛かっているのです。私たちが現在,ソフトウェア開発に苦労しているのは致し方ありません。
InfoQ: 結合度(coupling)や凝縮度(cohesion)など,設計の基礎を理解することが重要だと思うのはなぜですか?
Thompson: ソフトウェア開発を行なう上で,私たちが抱えている最大の課題のひとつは,アプリケーションの大規模化と,それに伴う複雑性の管理です。オブジェクトやコンポーネント,モジュール,あるいはシステムの結合度が高まれば,相互の影響度も大きくなります。その結果は,修正の難しさやエラーの伝搬,コンテンションに起因するスケール性の喪失,アクションの依存によるパフォーマンス上の問題など,さまざまな形で表面化します。時間的,空間的,実装的に疎結合であることが,スケールやレジエンスの面で不可欠なのです。結合度の高さは,ひとつのモジュールないしコンポーネントの変更が別のものに変化を引き起こすかどうかという,同時発生性によって容易に確認することが可能です。
凝縮度の問題は,結合度よりもさらに微妙です。凝縮度とは目的の一貫性である,というのが私の考えです。ひとつのコンポーネントを別々の方向に拡張することは,目的の一貫性を失うことであり,予期しない動作や特性へとつながる可能性があります。ソフトウェア設計における凝縮度の不足は,要件やチームのダイナミクスに問題があることを示すよい指標です。凝縮度の高い設計は,一般的にフォローしやすく,関連する関数や機能がグループ化されていて,お互いを見失うことがないため,フォローや探索も容易です。
よりよいソフトウェアエンジニアになるためには,基本的な設計スキルの向上を,日頃の開発作業の中心に置かなくてはなりません。こういったスキルを身に付けるためには,反復練習とコーチングが最善の方法です。
InfoQ: 分解(decomposition)や抽象化(abstraction)といった操作が,よりよいソフトウェアを書く上でどのように役立つのか,例をあげて頂けますか?
Thompson: ソフトウェア開発において,抽象化ほど誤って理解されているトピックはないと思います。ダイクストラは,抽象化とは“絶対的に正確であることが可能な新しい意味レベル”であるという,極めて説得力のある説明をしました。大部分の開発者は,この用語を完全に誤用しています。彼らが抽象化と呼んでいるのは,理解不足をごまかしているのに過ぎません。Joel Spolskyは,このような誤解を何とかして正当化しようとする行為を表現するために,抽象化の破綻の法則(the law of leaky abstractions)という言葉を生み出しました。Linuxカーネルのブロックデバイスやデバイスドライバのように,優れた抽象化の例はいくつもあります。しかし残念なことに,大部分のソフトウェア抽象化は,ある種の精神的自己満足の状態を作り出して終わることが少なくありません。正確性を向上させて理解を促進するというよりも,フランケンシュタイン博士の怪物のように,結果的にコードを理解しがたいものにしていています。完成度の低い抽象化は,単なるコピーよりも高くつくことが少なくないのです。
私たちは,ビジネスオブジェクトを明確かつ具体的な構成単位に分割した上で,高品質で結合度の低いコンポーネントを使ってソフトウェアを構築する技術を高める必要があります。営利企業は,自らのフレームワークに私たちを組み入れることで,顧客をロックインしたいと考えますが,これは誤った例です。営利を目的としたこのような展開は,高品質で保守性の高いソフトウェアの提供という目標とは相反することが多いのです。
ソフトウェア以外の技術分野を見れば,ツールは成果の提供プロセス自体よりも,むしろプロセスのサポートを目的として使用されるものであることが分かります。私たちは今,人日単価やCPU単位のライセンス,保守契約によるロックインを重視するビジネスを脱却すべき時期にいるという,その兆しが見えているように思われるのです。現在ではAmazonなどによって,必要性に応じたユーティリティコンピューティングの利用が実現しています。継続的インテグレーションや継続的デリバリといったモデルのサポート手段として,クラウドコンピューティングが優れていることは,ダイナミクスの変化や望ましい行動を推進する手段として,非常に注目すべき部分だと思います。同じような状況はツーリングにおいても,Jetbrainsなどに見ることができます。彼らは契約によってではなく,生産性を向上する製品を提供することで,ユーザを自社製品にロックインしているのです。
InfoQ: 欠陥の検出や改善を行なう方法として,コードを読むことに言及されていましたが,詳しく説明して頂けますか?
Thompson: 再考と洗練の継続的な実施は,どのような創造的活動においても望ましいことです。Eメールやエッセイ,ブログなどを書いた後で,もっと上手に書けるのではないかと思って読み返した経験はありませんか?これはごく自然な行動です。再検討することによるコンテキストの違いが,新たな洞察を与えてくれるのです。端的に言えば,私たちが書こうとしているものはすでに短期記憶から消え去っているはずなので,もう一度読み直して考える必要がある,ということです。その他に,情報量が増えている,世界が進展している,私たちの知識が増えているなども理由としてあげられます。
私はコードを,自分自身の現在の理解内容を書き留める場所と考えるようにしています。コードを読み直すことは,誰にでもある間違いを修正するためだというのは事実ですが,それだけではなく,私たちの理解度の向上を記録することもできるのです。アプリケーションはある意味で,ビジネスプロセスのシミュレーションでもあります。ビジネスプロセスの現時点での理解をソフトウェアが反映できていないのであれば,開発者によって“あるべき姿の想像(メンタルマッピング/mental mapping)”が行われた,ということになります。このメンタルマッピングが,プロジェクトの重荷になるのです。ドメイン駆動設計がソフトウェア開発における重要なツールである,と私が考える理由のひとつがここにあります。
自分のコードだけでなく,日頃からすべてのコードを読むようにしてください。他人のコードを読むことは非常によい勉強方法です。作家のStephen Kingは,“人が書いた本を読むことは,よい作者になる最善の方法”だ,と言っています。コードにも同じことが当てはまります。そしてオープンソースは,産業としての私たちが採用している最高のステップのひとつなのです。ソフトウェアをオープンに開発することで,理解を共有し,フィードバックを獲得し,他人から学ぶことができます。オープンソースに参加することは,エンジニアとして成長するための最良の方法なのです。
Martin Thompson氏はQCon London 2016で,“Engineering You”と題して講演し,優れたソフトウェアエンジニアの持つ特性について語るとともに,エンジニアとしての能力を引き出すための個人的なプラクティスやテクニックを探求した。
この記事を評価
- 編集者評
- 編集長対応