Sansan Tech Blog

Sansanのものづくりを支えるメンバーの技術やデザイン、プロダクトマネジメントの情報を発信

インターフェースに関する覚書 なめらかなプロダクト開発を目指して

はじめに

こんにちは。Eight事業部でエンジニアリングマネージャーというお仕事をしているkazu0620です。今回は、このブログに寄稿をできる機会を頂いたので、年明けくらいから何となく考えていた、インタフェースというものについての話をまとめてみました。

より良いDXを求めて

最近、巷でDXという言葉が流行しています。DXとは、ある特定のシステムを開発・保守する開発者をユーザーと捉え、彼ら・彼女らの開発に伴う体験を Developer Experience(DX)と呼ぶ、というものです。より良い体験をエンドユーザーに継続的に提供するための手段(あるいは前提条件)として、システムの開発者にとってより良いDXを提供できる環境を作ろう、という議論には、多くの開発者が同意するものと思います。

ただ、DXという言葉がカバーする範囲は非常に大きく、ソフトウェアの品質の話から、自動テストの有無、継続的インテグレーションや継続的デリバリーの話、心理的安全性や組織設計など多岐に渡ります。また、本当により良い開発体験を提供しようとするならば、手法やツールではなく人間自体に向き合う必要があるでしょう。

このようにDXは幅広い概念ですが、この記事では特にソフトウェア、あるいはソースコードのユーザーインタフェースという観点からプロダクト開発を覗いてみて、DXを多少なりとも向上させる方法について考えてみたいと思います。

また、最後には同じ考え方をもう少し広く適用してみて、プロダクト開発の過程の中に存在する様々なインタフェースというものについて考えてみます。

 

ソフトウェアのユーザーインタフェース

ソフトウェアのユーザーインタフェースというと、エンドユーザーが触れるアプリケーションの、グラフィカルなインタフェースのことをイメージする方もいるかもしれません。

しかし、この記事では前述のDXの文脈に基づいて、特定のシステムを開発・保守するソフトウェア開発者をユーザーと考え、そのユーザーが開発時にプログラムから利用するシステムのインタフェースに焦点を当てたいと思います。また、ここでいうインタフェースは、プログラミング言語の機能としてのインタフェースではなく、システムの利用者であるユーザーが、そのシステムを操作するためのプロトコルという意味においてのインタフェースのことを意図しています。

分かりやすい例でいうと、広義の意味での API(Application Programming Interface)は、あるシステムを別のシステムから操作するためのインタフェースです。あるサービスの Web API は、外部のシステムからそのサービスのシステムを操作するためのインターフェースであり、OSのライブラリが提供するAPIは、そのOS上で動作するアプリケーションが、OSの何かしらの機能を操作するためのインターフェースである、ということができるでしょう。

あるいはオブジェクト指向におけるクラスで考えると、公開されているプロパティやメソッドが、そのクラスを利用するユーザー(開発者)にとってのインタフェースであるといえます。ソフトウェアは通常そのようなクラスやモジュール、といった小さなサブシステムの集合によって成り立っているので、あるサブシステムを作りそのインターフェースを提供する開発者と、そのサブシステムを利用するユーザーは、同じ人物である、ということも多いでしょう。

このように、既に実装されたプログラムを利用する開発者をユーザーと捉えた時、そのユーザーから見たより良いインタフェースとは、一体どのようなものになるのでしょうか。

悪いインタフェースがもたらすコスト

まず、なぜそのようにユーザー視点でソフトウェアのインタフェースを考慮することが重要なのか?という点について理解するために、あえて極端に悪いインタフェースを持ったソフトウェアについて考えてみましょう。

例えば、呼び出した時に一体何が起こるのか想像すら出来ないような名前の関数がたくさん並んだライブラリのクラスを利用するシチュエーションを想像してみてください。あるいは、エンドポイントのURLからは想像もしないような振る舞いをする外部サービスの Web API(例えば、GETリクエストを投げて情報を取得しただけなのにデータを大きく更新する、など)を想像してみてください。

このような悪いインタフェースを持ったシステムと付き合うことになった場合、その振る舞いを「解読」しながら開発作業を進める必要があり、開発にかかるコストはその分大きくなってしまいます(もちろんDXも大きく損なうでしょう)。

そんなことは自明だと考える方も多いでしょうが、特に伝えたいのは、あるシステムの内部でしか利用されないクラスや Web API のインタフェースも、(程度は違うにせよ)同じく重要である、ということです。

例えば、特定のクラスや Web API を設計・実装した開発者と、それを利用する開発者が同じである場合、このインタフェースの重要性は見過ごされがちです。公開すべき操作とそれを利用するユーザーが、将来に渡って存在していることが明らかであるにもかかわらず、その重要性が見落とされてしまうのです。

もし記憶喪失になっても

アプリケーション内の特定のサブシステム、例えば何かしらの責務を持ったクラスを完成させた瞬間、実装した開発者はおそらくその内部について完全に把握しているでしょう。しかし、数ヶ月後に「実装者」ではなくそのクラスを利用する「ユーザー」として同じクラスに向き合ったとき、その内部の内部実装についてすっかり忘れていて、開発に苦慮する、というのはよくある話です。

ここで重要なのは、「内部実装の詳細を忘れていること」が問題なのではなく「内部実装を把握していなければ、利用できないようなインタフェースになっていたこと」が問題である、ということです。つまり、クラスが公開している関数やプロパティ、型の情報だけではそのクラスの動きや責務を把握できなかったがゆえに、そのクラスの振る舞いについて「解読」する必要が生じてしまい、結果として内部実装を読まざるを得なくなってしまっているのです。これはクラスが提供しているインタフェースが、十分に良いものであったならば、本来払う必要のなかったコストである、といえるでしょう。

では、どうすればそのような無駄なコストを払わずに済むだろうか、と考えると良いインタフェースの輪郭がおぼろげに浮かんできます。例えば極論ですが、あるクラスを実装した開発者が、ユーザーとしてそのクラスを利用するときに仮に記憶喪失となっていても、内部実装を見ずに公開されているインタフェースだけその使い方を理解できれば、それは良いインタフェースといえるのではないでしょうか。また、その理解にかかるコストが少なく直感的に理解できるものであれば、より良いインタフェースである、といえそうです。

良いインターフェース

ユーザーが使い方を理解するコストが少なく、またユーザーの理解通りに動作するものが良いインタフェースを持ったソフトウェアである、と考えてみると少なくともそれは次のような特徴を持っていそうです。

操作の対象が明瞭である

わかりやすいインタフェースを持ったソフトウェアは、自身が何を扱うものなのか、何に関心があるのか、について明瞭です。責務が明瞭、といっても良いかもしれません。オブジェクト指向でいうクラスであれば、そのクラス自体の名前や公開メソッドからクラスの責務を十分に理解できるよう作られていれば、クラスを利用するユーザーはそれが何を操作の対象としているのか(あるいは何のデータを表現したバリューオブジェクトやエンティティなのか)理解することができるでしょう。逆に、インタフェースを見ても何を操作(表現)するクラスなのか理解できない、あるいは操作(表現)の対象に論理的な整理がつかない、といった場合は良くないインタフェースである、といえるでしょう。

もしも良いインタフェースにしたい、と時間を使って考えてもその責務を明確にすることが難しいときは、そもそも前提となる設計に問題があることや、作ろうとしている機能のドメイン自体が正しく整理されてない、といったケースを疑ってみても良いかもしれません。

操作の内容が明瞭である

わかりやすいインタフェースを持ったソフトウェアは、公開されているインタフェースから、ある操作によって何が起きるのかをユーザーが理解できて、かつそれが期待通り動作します。また、その操作に副作用があるかどうかをインタフェースから判断することができます。

例えば、GETリクエストを実行したとき、データに対する操作が実行されてしまい、同じようにリクエストを投げているのに毎回異なる結果が返ってくる、といったようなAPIを考えてみましょう。このAPIは、利用する開発者、つまりユーザーがインタフェースから想像も期待もしない結果をもたらしており、良くないインタフェースを持ったソフトウェアといえるでしょう。通常、データの変更などの副作用が伴う処理であれば、POSTやPUTで表現されることを開発者は期待するはずです。

また、データを取得するならばそれがどんなデータであるのか、副作用をもたらす場合にはそれがどんな副作用であるのかを明瞭に示すことができれば、よりわかりやすいインタフェースを持ったソフトウェアといえます。

関数の名前や Web API のパスの構成から、その操作が理解できるように明瞭にしようとしても、そもそも行なっている操作自体が複雑なので難しい、といったことも時にはあるかと思います。当然ながらどうしても複雑で致し方ない場面もありますが、そんなときは一度手を止めて、設計の段階や機能自体のドメイン的な整理に問題がある、といった可能性がないか立ち戻って考えてみるのも良いでしょう。

操作方法がシンプルである

一般的なプロダクトと同じく、ソフトウェアのインタフェースも当然ながらシンプルな方がユーザーにとって、使いやすいものとなります。例えばモードやステータスのフラグによって、同じ関数を呼び出しても挙動が全く変わったり、特定のモードでないと呼び出せない関数がある(呼び出すとエラーになる)ようなクラスは、ユーザーにとってあまり使いやすいものではないことが多いでしょう。

また、クラスの内部でだけ実行すれば良いような処理が外に公開されているケースも、ユーザーがそのクラスの使い方を理解するためのコストを高めてしまいます。ソフトウェアは現実世界で使われるプロダクトを作るための手段であり、現実世界は常に複雑なものです。

よほど意識しないと(あるいはしても)ソフトウェアは複雑になりがちなので、インタフェースがそのシンプルさを保つことができているか、については考慮してもしすぎることはないでしょう。

ユーザーに暗黙知を要求しない

インタフェースを複雑にする最も簡単な方法は、おそらくユーザーに暗黙知を要求することです。例えば、特定の順番で複数の関数を呼び出さなければ期待する動作が得られない、といった前提を持つオブジェクト志向のクラスがあったとして、公開されている関数の並びや名前だけからその事実を読み取ることは難しいでしょう。

もちろん、ソースコードのコメントやドキュメントにその旨が書かれていれば救いはありますが、それも無かった場合、ユーザーは内部の実装を見ない限りそのシステムを正しく利用することはできません。

このように、インタフェースで公開されていない、あるいは表現できない暗黙のルールは例え小さなものでも、ユーザーがそのソフトウェアを利用するためのコストを非常に大きくしてしまいます。

ユニットテストはユーザー視点を培う

上記のように利用するユーザーにとって良いインタフェースとはどんなものか、その方向性を理解してもなお、慣れないうちは実際にそのように作るのは難しいものです。

プロダクトを利用するエンドユーザーの視点に立ってものづくりをしながら、さらにその過程で作る1つ1つの小さなコンポーネントを利用するユーザーの視点にも立つ、というのは確かに簡単ではない作業です。プログラミングを学び出してから日が浅く、コードを書いた経験・他者が書いたコードをユーザーとして利用した経験が少なければ、それはさらに難しく感じるでしょう。

そんな時にオススメしたいのは、実装に入る前に開発しようとしているプログラムのユニットテストを書くことです。ユニットテストは、テストの対象となる機能のインタフェースを通じて実際にそれを操作し、期待通りに対象が動作するかどうかを確認するためのコードを書き、実行するものです。

つまり、ユニットテストを書くためには、そのソフトウェアがどんなインタフェースを持つのかを考えて決めておく必要があります。さらに、テストの中でそのインタフェースを利用する処理を書くので、実装に入る前に、対象のソフトウェアを実際に「ユーザーとして使う」という体験を経ることができます。

つまり、インタフェースを考え、ユーザーとしてそれを使ってみて、手触りによってはインタフェースを変更する、という流れを終えてから、本格的なプログラムの実装に入ることができるのです。

ユニットテストを書くことには他にも多くのメリットがありますが、このように良いインタフェースを設計する、という観点でもその恩恵は大きなものであるといえるでしょう。

小さな道具と大きなソフトウェア

前述したように、ソフトウェアというものは小さなサブシステムの集合から成り立っています。それらのサブシステムの一つ一つにインタフェースがあり、それを利用するユーザーがいると考えると、プログラミングは再利用可能な小さな道具を作りながら、それらの相互作用によって全体としてのプロダクトを作る営み、とも言えます。

また、現代におけるソフトウェア開発は、リリースが完了してプロジェクトが終了する、ということはほとんどありません。多くのプロダクトにおいて、リリースは全ての始まりでしかなく、エンドユーザーのフィードバックを受けながら、そのプロダクトの在り方を変えていく、という不断の作業を求められます。つまり、私たちが一度作ったクラスやモジュールといったプログラムは、将来に渡って使われる可能性が極めて高い道具である、ということができます。

どれだけ大きなソフトウェアであっても、原則としてはそのような継続的に利用される小さな道具の集合と言えるのではないでしょうか。

道具の品質とプロダクトの品質

上記のようなことを前提と考えると、複雑で使いづらいインタフェースのプログラムを作るということは、複雑で使いづらい道具を生み出し、将来の自分や仲間に、それを利用することを強いるようなものです。

奇妙で手に持ちづらい形だが一応使える、というような金槌で犬小屋を作ることはできるかもしれません。しかし、それで大きな建造物を作ることは難しいでしょう。道具として機能は果たすものの良くないインタフェースを持ったプログラムも、同じように考えることができるかもしれません。

歪なインタフェースを持ったプログラムの集合でも、小さなプロダクトをリリースすることは出来るし、その時点で問題になることもないでしょう。しかし、それをユーザーのフィードバックを見ながら継続的に開発して、世の中や人々に影響を与える大きなプロダクトに育てようとしたとき、やはり歪な道具の集合では、複雑さの限界に突き当たってしまうのではないかと私は考えています。

悪い道具に慣れるということ

悪い道具を利用するデメリットは、実は単純にそれが使いづらいことだけではありません。人間とは良くできたもので、使いづらい道具があったとしても、それを使わざるを得なくなったとき、道具に人間の方を合わせて最適化してしまうものです。

例えば、私が今この記事を書くのに利用しているiMacには、さる事情があって先週から画面に大きなひび割れが入っています。このひび割れが入った日こそ気になって集中できなかったのですが、今ではこのひび割れを意識することは、ほとんどなくなってしまいました。それは、おそらく私がひび割れの部分にウィンドウを配置せずに使う技術を無意識のうちに身につけてしまったためです。また、視覚的にもひび割れている状態に慣れてしまったため、という部分もあるでしょう。

このように、人は不自由な道具を使うことを強いられると、無意識のうちに自分をその道具のインタフェースに合わせて自身を最適化してしてしまうことがあります。ここで重要なのは、私はすでにiMacのひび割れは気にならなくなりましたが、それによって失われた生産性が回復されたわけではない、という点です。然るべき処理(おそらくは始末書を書く、などといった行為が必要となる)を行なって新しいiMacに切り替えると、私はひび割れのない液晶の圧倒的な使いやすさに感動することでしょう。

道具の歪さは、やがて連鎖する

同じように、一度作ってしまった粗悪なインタフェースを持つプログラムも、最初は使いづらさを感じるものの、ユーザーとしてそれを利用するうちに、いつの間にか慣れてしまう、といったケースがあります。

しかし、そのような不適切なインタフェースを持つ道具をストレスなく使いこなせるようになったとしても、やはり適切に設計されたインタフェースを持つプログラムを利用したときと比べるとその生産性は下がるはずです。また、新しいメンバーがプロジェクトにアサインされる度に、そのインタフェースに慣れるためのコストを払い続けることになるでしょう。

さらに問題となるのは、不適切なインタフェースを持った道具を使い続けた結果、それに疑問を抱かなくなり、自身も不適切なインタフェースのプログラムを生み出してしまう、といったケースです。そうした場合、ソフトウェアのメンテナンスにかかるコストは指数関数的に複雑になり、道具の歪さは、やがてプロダクトの表面にも何かしらの形で現れるはずです。

やはり、最初から適切なインタフェースを設計すること、またユーザーとして利用したプログラムが不適切なインタフェースであると感じた時には積極的にリファクタリングを行うことが重要と言えるでしょう。

境界があるところにインタフェースはある

これまで、私たちはソフトウェアの部品をユーザーとして利用するときに、そのインタフェースを良いものにすることがなぜ重要なのか、良いインタフェースとはどういうものなのか、といった点ついて考えてきました。次に、この考え方をもう少し広いスコープで適用してみる、という試みを行ってみたいと思います。

ユーザーインタフェースは、あるシステムから別のシステムを利用するときに、どのように情報をやりとりしたり、操作するのかを定義したプロトコルのことを意味していたのでした。つまり、2つの異なるシステムが存在していて、それらが接する境界にはインタフェースがある、ということです。

これまでは、ソフトウェアのプログラムから、オブジェクトや Web API といった別のシステムを利用したり操作するケースのことを話してきました。例えばこのシステム、という言葉の解釈をソフトウェアに閉じた世界からもう少し広げてみて、プロダクトを開発するための組織、あるいはチームを1つの大きなシステムとみなしてみると、いったいどんな物の見方ができるでしょうか。

組織内のサブシステムとインタフェース

通常プロダクトは、プランニングやマーケティング、開発やデザインといった異なる職能を持つメンバーが集まり、それらの能力を合わせることで作られています。

これは見方によっては、1つのソフトウェアの中にも、オブジェクトや関数といったようにたくさんの小さなサブシステムがあったのと同じように、プロダクトを作る機能を持った1つの大きなシステムの中に、マーケティングを担う機能を持ったサブシステムや、開発を担う機能をもったサブシステムがある、とも捉えることができます。

さきほど、2つの異なるシステムが存在していて、それらが接している境界にはインタフェースがある、という話をしました。ということは、開発やプランニング、デザインといったプロダクト開発の機能をサブシステムと捉えると、それが接する境界にもやはりインタフェースがありそうだ、ということがわかります。

つまりこれらサブシステム間の境界を、私たちが普段一体どのようにとりもっているのかという点に着目すれば、そこにどんなインタフェースがあるのか、それをどう改善することができるのか、見つめることができそうです。

コミュニケーションをデザインする

開発者とプランナー、あるいは開発者とデザイナーといった異なる機能を持つチームやメンバーが、どうやって協調して1つの仕事を進めているのかと考えると、そこにあるのは当然何かしらのコミュニケーションです。コミュニケーションを行うことなく、上で例えたようなサブシステムの境界を超えて、何かしらのアウトプットを出すことは、まず不可能でしょう。

であれば、このコミュニケーションのプロトコルを、組織内のサブシステム間のインタフェース、と表現しても差し支えはないのではないでしょうか。どうやってプランナーが開発者にものを伝えるのか。あるいは開発者がどうやってプランナーにものを伝えるのか。それはSlackのチャンネルかもしれないし、GitHubのISSUEを通してかもしれないし、あるいはただの雑談を通じてかもしれません。

このようなコミュニケーションをどうやってデザインするか、ということがプロダクト開発におけるサブシステム間のインタフェースの設計なのではないかと、私は考えています。

組織のインタフェースをリファクタリングする

上で例えたような組織内のサブシステム間のコミュニケーションのプロトコルは、組織によっては明確に文章やルールとして定義されていることもあるし、あるいはそのほとんどが慣習という暗黙的な定義しかないこともあるでしょう。

そうしたインタフェースの良し悪しに対する考え方は、これまで述べたようなソフトウェアのインタフェースと全く同じではないでしょうが、共通する部分は多くありそうです。

例えば、暗黙的なルールのあるインタフェースは複雑で使いづらい、という法則はコミュニケーションのデザインにおいても同様に機能しそうです。また、不要に細かくルールが決まって、シンプルさが損なわれているようなインタフェースであった場合も、やはりそれが理解しやすい、とは言えないでしょう。

こうしたコミュニケーションをデザインし、良いインタフェースに保っておくことは、プログラムのサブスシステムのインタフェースをより良いものにすることと同じか、それ以上に重要です。

プランナーやデザイナーが開発と接するインタフェースは、それを利用する「ユーザー」という視点から見て最適なものになっているのか。例えば機能仕様の共有方法、Slackのチャンネルの設計、機能のユースケースをやり取りする GitHub ISSUE のテンプレート、そうしたものをより使いやすいインタフェースに「リファクタリング」する余地はないか。

私たち開発者は、ともすると開発という領域に閉じて考えてしまいますが、時にはこのように組織や開発プロセスを、いっそシステムと考え抽象化して見つめてみると、思いもよらぬ改善点が見つかるかもしません。

なめらかなプロダクト開発を目指して

世の中には、プロダクトのUI/UXに強く関心を持った、優秀な開発者が驚くほど数多くいます。

そんな優秀な開発者のみなさんが、エンドユーザーの視点でプロダクト開発を考えるのと同じように、ソフトウェア内のサブシステムのインタフェースや、組織内に存在する様々なインタフェースをユーザー視点で改善することができるように、もしもなれば。

いろんなプロダクトの開発のプロセスが、もっとなめらかになるかもしれない、より良いDXを提供する環境を作ることができるかもしれない。もっと便利なプロダクトや、使いやすいプロダクトが世に増えるかもしれない。

そんなことを考えて、この記事をまとめてみました。短くはない文章を、ここまで読んで頂き、ありがとうございます。

最後に、もしも私たちと一緒に、これまで書いたようなことを、悩み、考えたい、という方がいれば、ぜひSansanという会社に一度遊びに来てみてください。Sansanはまだまだプロダクトたちも、開発プロセスも、目指すべき理想と比べると全く不完全な状態です。でも、それを一緒に足掻きながら改善したい、という仲間を大募集しています。

© Sansan, Inc.