チーム開発の視点が変わる アジャイル開発の新常識 第10回 アジャイルアーキテクトの心得

アジャイル/DevOps

2022.03.31

  

*本コラムは、技術評論社「Software Design」2021年9月号に寄稿したコラムを掲載しています。

はじめに

みなさんのアジャイル開発現場では、どんなツールを使っていますか? システム開発のためのツールは、クラウド、ライブラリ、パッケージ、言語、フレームワークなど、具体的に挙げたらキリがないでしょう。これらのツールは、たいていそのままではユーザー要求を満たせないので、連携させたり、カスタマイズしたり、コードを書いたりして、要求を満たすシステムを設計して、構築していきます。
では、みなさんは、なぜそのツールを採用したのか、なぜそのようなシステム設計にしたのか、明確に答えられますか? 「とりあえず」過去のプロジェクトでうまく動いたのでこういう設計にした、とか、「なんとなく」アジャイル界隈ではやっているからこのツールを採用したという方が多いのではないでしょうか? 確かにデファクトスタンダードになっているツールや、うまくいった設計を採用することは間違っていませんし、それでもプロジェクトは問題なく進んでいくことでしょう。
しかし、アジャイル開発をしているエンジニアであれば、刻々と変化していくビジネス環境に対してスピーディーに適応していかなくてはいけません。「とりあえず」「なんとなく」な理由でツールや設計を採用したせいで、変化に適応できず、生産性がどんどん下がっていったチームを数多く見てきました。本記事では、アジャイル開発におけるアーキテクトとして、どのような指針に従ってツール選定や設計を進めていけばよいか、具体例を挙げて説明していきます。

アジャイル開発のアーキテクトの役割とは?

アジャイル開発におけるアーキテクトを考える前に、そもそもシステム開発における「一般的なアーキテクト」とはどのような役割を持つのかを見ていきましょう。

一般的なアーキテクトの役割

IPAが定義するITスキル標準におけるITアーキテクトは、次のように説明されています注1

ビジネス及びIT上の課題を分析し、ソリューションを構成する情報システム化要件として再構成する。ハードウェア、ソフトウェア関連技術(アプリケーション関連技術、メソドロジ)を活用し、顧客のビジネス戦略を実現するために情報システム全体の品質(整合性、一貫性等)を保ったITアーキテクチャを設計する。設計したアーキテクチャが課題に対するソリューションを構成することを確認するとともに、後続の開発、導入が可能であることを確認する。また、ソリューションを構成するために情報システムが満たすべき基準を明らかにする。さらに実現性に対する技術リスクについて事前に影響を評価する。

いまいちピンと来ないかもしれませんが、平たく言えば、さまざまなITの制約がある中で、ビジネス要件をシステムとして実現する方法を考える人、ということのようです。ここで重要なのは、実現する方法には、「動かす方法」「開発する方法」「届ける方法」の大きく3つの意味があるということです。ITアーキテクトの説明に、「後続の開発、導入が可能であることを確認する」とあるように、システムを動かすだけでなく、どうやって開発してリリースするかまでを考えるのがアーキテクトの役割です

アジャイルの定義からアーキテクトのあるべき姿を考えてみる

IPAのITアーキテクトの定義には、開発手法への言及がありません。しかしながら、開発手法によって、「動かす方法」「開発する方法」「届ける方法」に差が出るだろうということは容易に想像できます。
では、その差は何でしょうか? 「アジャイル宣言の背後にある原則」注2には、アーキテクトの役割を考えるために役立ちそうなヒントが記載されています。同サイトから抜粋した、次の3つの観点をもとに考えてみたいと思います。

価値のあるソフトウェアを早く継続的に提供します。
要求の変更はたとえ開発の後期であっても歓迎します。
(中略)
シンプルさ(ムダなく作れる量を最大限にすること)が本質です。

では、1つずつ見ていきましょう。
1つめはまず、「価値あるソフトウェア」とあります。そもそも、価値があるとはどういうことでしょうか。逆を考えるとわかりやすいと思います。たとえば、何らかの情報をWeb画面で入力して登録するようなシステムがあったとき、画面は完成していてもデータベースと接続されておらず、入力しても情報が消えてしまうシステムに価値はあるでしょうか? 価値がある、とは、システムの利用者にとって価値がある、ということです。次に、そのソフトウェアを「早く提供します」とあります。前述の例のような価値あるシステムを早く提供するためにはどうしたらいいでしょうか。画面が1つ程度であれば早く提供できるかもしれませんが、「登録した情報を一覧で見る」など、たいてい複数の画面が連動して利用者にとっての価値を生み出すため、価値あるシステムを早く提供するためには工夫が必要そうです。また、それを「継続的に提供します」とあります。小さなシステムであればリリース作業は短時間で済みますが、大きなシステムでは入念な計画を立てなくてはいけないし、ものによっては数々の面倒な承認フローを通らなくてはいけません。「継続的に」ということは高頻度で複数回実施されるものですので、リリース作業には多くのコストを割けないでしょう。
まとめると、「小さな価値の単位で低コストで頻繁にリリースができること」が重要であることがわかります。
2つめは、 「変更を歓迎しろ」とあります。みなさん、仕様変更は好きですか? 嫌いだという方は、きっと、仕様変更にまつわる苦い思い出があるからでしょう。しかし、変更を予想して万全な備えをしているところに仕様変更の依頼が来たらどうでしょうか。こんなこともあろうかと、と叫び、喜々として変更を受け入れるのではないでしょうか? 少なくとも筆者はそうです。つまり、変更を歓迎するためには「変更容易性を高めておくこと」が重要であることがわかります。
3つめは、「シンプルさが本質」とあります。複雑なものと比べて、シンプルなものは何が良いのでしょうか。それは、人間が扱いやすい、の一言に尽きると思います。複雑なものは、理解したり、利用したり、加工したりするのに多くの時間を要します。それは変更容易性を低下させるでしょう。
また、別の問題もあります。みなさん、エントロピー増大の法則は知っていますか? エントロピーとは「乱雑さの程度」を意味する物理学の用語で、物体は時間の経過によって秩序あるものから無秩序になるという法則です。みなさんが普段使っている作業用の机を想像するとわかりやすいと思います。最初は整理整頓されていて作業もはかどると思いますが、作業が進むにつれてどんどん机の上が乱れていき、最初に比べて作業の効率が下がっていきませんか?
最初はシンプルなアーキテクチャでも、開発の進捗にともなって時間が経つにつれ、どんどん複雑さが増していきます。そのため「シンプルさを継続的に維持すること」が重要なのです。

アジャイルアーキテクトとしての設計思想

アジャイル開発のアーキテクトとしての重要な指針がわかりました。

  • 変更容易性を高めておくこと
  • 小さな価値の単位で低コストで頻繁にリリースができること
  • シンプルさを継続的に維持すること

では、それを「動かす方法」「開発する方法」「届ける方法」に当てはめたとき、具体的にどうすればよいでしょうか。まずは、3つの方法をシステム開発の身近で代表的な技術要素に置きかえ、それぞれの要素ごとに説明していきましょう。
「動かす方法」は、機能要求・非機能要求を満たすためのインフラ・ソフトウェアの構成を定義するシステムアーキテクチャ、そして機能内の構造を定義するソフトウェアアーキテクチャがあります。「開発する方法」は、システム開発であれば、開発言語とフレームワークが代表的でしょう。「届ける方法」は、リリース作業が挙げられます。

システムアーキテクチャ

システムアーキテクチャはシステムを実現するために必要な機能・サービスをどのように配置し、どのように相互連携するかの方針を指し示すことになります。システムアーキテクチャを検討するうえで重要なポイントは、あらかじめシステムの行く末を視野に入れ、要求に応じて拡張可能な構成を採ることです。

  • 具体例
    具体例として、何かの画像データを収集して管理するシステム開発を挙げます。システムアーキテクチャとして画像データをWeb APIで文字列として受け取り、SQLiteを用いた軽量データベースサーバにそのまま文字列形式で投入するという方式を採用しました。これは、このシステムを動作させるインフラが今後変更される可能性を考慮しポータビリティ(システムの移植性、可搬性)を良くしたいという要求を、管理情報や画像を含むすべてのデータを単一のデータベースファイルに保持することで実現できると考えたからです。
    さて、無事リリースでき、うまく動作していましたが、あっという間にデータベースのサイズが数十GBと膨れ上がってしまい、むしろポータビリティが低下するという結果になってしまいました。また、保管先を別のものに変更しようとしても、画像データが文字列に変換されてしまっているため、選択の幅も狭まってしまいました。
  • どうすればよかったか?
    データ量が増えていくことが想定できていたのに、SQLiteという軽量データベースを選定しまったというのも問題でしたが、それよりも、「画像データを文字列として受け取り保管する」というデータベースの保管方式に依存したアーキテクチャが、データベース自体の変更可能性を低下させてしまったことが大きな問題です。たとえば、画像は画像ファイルとして受け取り、データベースに保管する直前に文字列に変換するようなアーキテクチャにしていれば、仮に途中で別のデータベースやストレージサーバなどに保管先に変更したとしても、変更は局所的であったはずです。

ソフトウェアアーキテクチャ

ソフトウェアアーキテクチャの設計では、画面を表示する、データを蓄積する、といった各要求に対してソフトウェアとしてどう実現するかを検討します。開発において最も変更が入りやすいポイントがこのソフトウェアの実装です。機能間で共通している点、言い換えれば、機能によって変わりづらい点をソフトウェアアーキテクチャとして規定していきます。

  • 具体例
    あるシステムは、Web APIとそのAPIを呼ぶWeb UIで構成されていて、開発チーム内の各メンバーは、Web APIとWeb UIを分担して開発していました。Web APIを担当している開発者は、「変更容易性を高めるために、いずれUIが変更されることを見越してどんなものでも受け付けられるAPIにしておこう」と思い、APIにどんどん機能を付け足し、本来3個で実現できるWeb APIの引数が最終的には10個になりました。
    いざUIと結合する際に問題が発生しました。引数が期待していた数よりはるかに多く、UI側の開発者は混乱し、動かせるようになるまでに非常に時間がかかってしまいました。また、バグが発見されたものの、何が問題なのか、原因調査も難航しました。
  • どうすればよかったか?
    変更可能性を担保するといった目的に対して間違ったアクションを取ってしまったことが問題です。必要なことを必要なときにといったシンプルさを維持するための方針はともすれば各開発者の誤解を招くこととなり、今回の例では必要なときに必要なインターフェースを規定し、インターフェースの引数も必要最低限にするというのが正しい方針の適用方法でした。
    アジャイル開発において、YAGNI原則という設計指針があります。これは、「今の時点で必要のない機能は付けるな、必要になってから付けろ」という指針であり、良かれと思って追加した機能が結局使われないことや、ソフトウェアの複雑性を増してしまうという問題です。アジャイル開発におけるコーディング、設計指針については多くの人が多くの見解を出しており、プロジェクトに応じてどう適用するかはアーキテクトとして選定していく必要があります。

実装言語とフレームワーク

実装言語とフレームワークは、開発者にとってのいわばメインウェポンです。選定するにあたって大事なポイントは、どの言語やフレームワークを選択しても要求を実現するために必要な機能性という側面では大きな違いはないという点です。もちろん、機能・非機能要求に対する実現のしやすさには差があると思いますが、開発チームにとっての習熟度や使い勝手を重視して検討していくことが多いでしょう。

  • 具体例
    あるWeb APIを作るために開発チームを立ち上げました。顧客の要求を満たすためにはどの言語を使っても問題ないという状況だったため、開発チーム内でどの言語が得意か意見を出し合い(図1)、多数決でJavaに決まりました。JavaでWebのAPIを実装していたところ、プロダクトオーナーから、Web APIを実行して結果が見られるような簡単なUIがほしいと依頼されました。メンバーの1人が、自分が得意だからという理由でUIをPythonで作りました。UIを見せることでステークホルダーからUIに関する要求が増えてきました。リッチなUIを実現する必要があったため、さらにほかのメンバーの1人が経験がないから使ってみたいという理由でReactを導入しました。
    その後、開発を進めていくと、Web APIのみを実装していたころに比べ、チームの生産性がガタ落ちしてしまいました。チームの面々が実装言語やフレームワークに慣れていなかったことや、ソフトウェアアーキテクチャが複雑化したことにより、ソースコードのメンテナンス性が下がってしまったのです。さらに、Javaだけ動かせればよかったインフラにも変更が加わったことでインフラアーキテクチャも複雑化し、リリースのコストも増大してしまいました。

    図1 実装言語やフレームワークに対する意見はさまざま
    図1 実装言語やフレームワークに対する意見はさまざま

  • どうすればよかったか?
    ソフトウェアアーキテクチャの例と同様ですが、実装言語をどうするか、フレームワークをどうするかといった観点は開発チームとしてパフォーマンスが出せるかの観点で選定するべきです。もちろん、実装言語やフレームワークの特徴をふまえて使い分けること自体には十分な意味がありますが、アーキテクチャの複雑性も増し、変更容易性やリリースのコストに影響を及ぼすということに注意しましょう。

リリース

顧客に届けるためには、開発したプロダクトをビルドして顧客が触れる場所にデプロイしなければなりません。このような一連の作業を一般的にリリースと呼び、実施する作業内容は、アーキテクチャや組織のルールに大きく依存します。近年でこの作業を手動で実施している現場はほとんどなく、継続的インテグレーションもしくは継続的デリバリ(以下、CI/CD)のしくみを導入しているでしょう。

  • 具体例
    高頻度で変更が入り、週に2~3 回程度のリリースが必要なシステムを開発しているチームがあります。一部のユニットテストやデプロイなどの作業は自動化されていたものの、手動の作業も多く残っていたため、リリースのたびに多くの時間が割かれることに課題を感じていました。そこであるとき、チームは意を決して十分な時間を取り、ボタン1つですべてのリリース作業が完了できるように自動化しました。その後は、これまで1時間かかっていたリリース作業が1分で終わるようになりました。
    しかし、開発が進み、ある要求を実現するため、システムのインフラに新しいミドルウェアを組み込むことになりました。リリースのための自動化スクリプトを変更しようとしたら、スクリプトが難解過ぎて結局手を入れられず、そのミドルウェアだけ手動でリリースすることになり、かえって面倒になってしまいました。
  • どうすればよかったか?
    実装コードとテストコードの関係のように、アーキテクチャとCI/CDのしくみは密に関係しているため、アーキテクチャの変更を見越して、CI/CDのしくみも変更容易性を高めておくべきでした。
    CI/CDは自動化すること自体が目的でなく、システムの変更のたびに実施するリリースのコストを削減するというのが本来の目的です。システムの変更とは、ソースコードの変更だけでなく、インフラやシステム、ソフトウェアのアーキテクチャに対する変更も想定すべきです。

誰がいつアーキテクチャを決めるのか

ここまで読み進めて、疑問に思った方もいるでしょう。いったい、アーキテクトは誰がやればいいのでしょうか? スクラムでは、プロダクトオーナー、スクラムマスター、開発者のロールのみで、アーキテクトというロールはありません。また、仮にアーキテクトが決まったとして、アーキテクチャはいつ決めればよいのでしょうか?
現実的には、プロジェクトの開始前に、プロダクトオーナーがデキる技術者をつかまえ、ユーザーの要求を伝え、検討してもらうことが多いでしょう。そのデキる技術者は、そのままスクラムマスターや開発者になることもあれば、その場限りで別のプロジェクトに入ってしまうこともあります。もしくは、プロダクトオーナー自身がアーキテクチャを決めてしまうこともあります。
しかし、このやり方で決めたアーキテクチャは、果たしてスクラムチーム全員が納得できるものでしょうか? スクラムチームは価値あるソフトウェアを顧客に届けることに対して、すべての責任を負います。誰か1人の一存で決めたものが原因で問題が起きたときは、決定者に対して責任を追及してしまいがちです。それは責任をチームで共有し信頼関係を重視するスクラムにとって良くない状況です。
ではどうすればよいのでしょうか。ここでアジャイルソフトウェア開発宣言の記述を見てみましょう。

最良のアーキテクチャ・要求・設計は、自己組織的なチームから生み出されます。

この記述を言い換えれば、スクラムチームが自己組織化されていれば、最良なアーキテクチャが成果としてアウトプットされるということです。アーキテクチャをとにかく先に決めたくなる気持ちは十分わかりますが、まずはスクラムチームが互いに信頼関係を築き、自己組織化を目指していくべきだと筆者は考えます。

まとめ

アジャイル開発のアーキテクトとしての考え方は理解できたでしょうか。正直、動かす方法を考えるだけでも精一杯なのに、こんなことまで考慮できない、と思った方も多いのではないでしょうか。
そこでみなさん思い出してください。スクラムは問題を早期に発見するためのフレームワークです。最初から100点のアーキテクチャを作り上げることは非常に困難です。それよりも、正しいスクラムを実践しながら、この記事で示した指針をもとに100点を目指して検査と適応を繰り返し、理想的なアーキテクチャに向けて継続的に改善していきましょう。

用語解説
  • スクラム:アジャイル開発手法の1つ。複雑なプロダクトを開発・提供・保守するためのフレームワーク
  • スクラムマスター:スクラムでの開発を進めるにあたり、開発を阻害する要因を排除する役割
  • プロダクトオーナー:プロダクトの中でどの作業を優先して進めていくかなど、プロダクトに対して責任を持つ役割
  • 自己組織化:リーダーのいないスクラム開発において、個々のチームメンバーが自発的に動くように成長していくこと

アジャイルコラム記事一覧

https://www.intellilink.co.jp/column/agile-devops.aspx

※図は技術評論社の許諾を得て掲載しています。