サービス立ち上げ時期の技術/プロダクトの選定をうまくやる

実は [Recruit Engineers Advent Calendar 2017](https://adventar.org/calendars/2324)の9日目です。

技術とプロダクトを「うまく選ぶ」のは非常に大変で、しかもそのサービスの方向性を決めかねない重要な要素です。

特に立ち上げの時期において、いかにして技術やプロダクトを選定するか、あるいは適当に選定するとどんなことに陥ってしまうかを、反省を込めて紹介したいと思います。

結果的に必要だったポイントは、以下の2つだったのかなと思います。

* 攻め込む部分と守る部分のバランスを見極める
* 入れ替え可能にする

ここでは、それぞれを紹介していきたいと思います。

# 選定のポイント

## 攻め込む部分と守る部分のバランスを見極める

### そのサービスの要件は？

特にサービス立ち上げの時期は、何も決まっていません。言い換えれば、何でも好きに決めることができる状態です。なんらかの制約があって、「こうしなければならない」というものがあるならともかく、そうでない場合は、星の数ほどある選択肢から絞り込んで選定をしなければなりません。

そんな時に選定の鍵になるのは、やはりサービスの要件だと思います。例えば、以下のようなものです。

* 24時間365日稼働が必須
* データのロストを許さない
* 障害時も数秒で切り替わる
* そもそもかけられるコスト

これらの要素によって自ずとプロダクトの幅は狭くなってきます。
逆に言うと、そこだけは絶対に外してはならず、そこに技術者の遊びやチャレンジ要素があってはなりません。
SIerの業界であれば当然だと思いますが、世の中にはビジョンだけがあって「あとはいい感じで」というケースも往々にしてあるでしょうから、**そのサービスが何を目指していてどこまでを頑張るのかは、最初にできるだけ話し合って決めたほうがよい**と思います。

これを厳密にしないと、技術者であればあるほど欲が出てきて、守らなければいけないところに謎のチャレンジ要素を入れてしまい、あとで困る羽目になります(なりました)。

### そのサービスで解決したい課題は？

同じような意味で、そのサービスの位置づけや戦略もある程度把握する必要があります。

例えば、自社の技術を広く知らしめるために、特定の技術を使っていることをアピールしたいのであれば、安定性重視で固くやってSLAを守るよりも、もっと他のところに目指すところがある、ということになります。

別の話で、例えば既存サービスのリプレースみたいな話になると、「これまで抱えていた課題を解決したい」という話も出てくるでしょう。

* 複雑化した構成要素を極力シンプルにして分かりやすくしたい
* リリース時にサービスを全停止してしまうのをやめたい
* リリース作業が死ぬほど大変で時間がかかるのを簡素化したい

こうしたものも、広義の要件として加えてしまったほうが分かりやすくなります。

### ポイントだけ押さえて素早く決める

そもそも何も決まっていない状態から、業務特性や指向に合わせてプロダクトや技術を選ぶということは、それだけでかなりの負担になります。

* そもそも要件は何なのか
* どういう技術要素があるか
* その要素の中でどんなプロダクトがあるか
* そのプロダクトは本当に思った通りに動くのか
* そのプロダクトは将来に渡って信用できるか

それらが全て、無限の時間の中で慎重に選べたのだとすると、きっとよいサービスになるでしょうが、…果たしてそうでしょうか？そうこうしている間にもライバルは先に進んでいるかもしれません。

そうした時に、そのサービスのあらゆる要素でいちいち考えていては、いつまで経ってもサービスは世に送り出すことができません。こだわりたい気持ちはわかりますが、**どうでもいい要素はとりあえず安定したプロダクトにしておく**、というのは一つの手です。時間をかけるべきところにかけたほうが健全です。

## 入れ替え可能にする

### 失敗しないのではなく失敗に強くする

人間は誰だって失敗が怖いもので、「不正解」なんて選びたくないものです。ただ、技術/プロダクト選定においても同じことがいえますが、100%の正解の啓示を与えてくださる神など存在しません。
今この時点で正解と思える選択が、1週間後には不正解になるなんてことはザラにあります。

結局、何をやっても100%の正解なんて誰も分からないのだから、**何が起こっても簡単に入れ替えやすくする**、というのが一番です。そのためには、そのプロダクトや技術要素の及ぶ範囲を極小化します。逆に、広範に渡れば渡るほど、その要素の入れ替えは困難を極めます。

### 根幹を担うものほど検証する

とはいえ、それを言うのは簡単ですが、例えば一貫性を持ったデータをもつデータベースだったり、コンポーネント間の通信を担うインターフェース仕様だったり、往々にして問題となるのは「変えられない」部分だったりします。そうした「入れ替えが難しい要素」であればあるほど、検証を簡単にでも行った方がよいです。

極端な例かもしれませんが、例えば「マイクロサービスアーキテクチャ」とか「サーバレスアーキテクチャ」って格好いいですよね。Dockerとか使いたいですよね。そこまでいかなくても、AWSやGCPを使ってイケてるプロダクトを作りたいですよね。…ということになったとき、こうした要素は一度選んでしまうと簡単にはやめることができません。

こうした要素であるほど、最初に伝えた「要件」などをもとに、検証を行ったうえで慎重に選択したほうがよいです。「**よく分からないけど、世の中ではいっぱい使われてるし、あの有名サービスも使ってるんだから大丈夫だろう**」と、キラキラした要素だけに注目して選ぶのが最悪です。
世の中には「使ってみた」という記事が溢れていますが、使ってみてトラブルが起こったことがまとまって公開されることはほとんどありません(あったとしても、他の記事に埋もれて探せません)。そうした時に、自分で検証もせずに判断してしまうと、やめるにやめられない要素でもあることから、長期に渡って技術的負債となる可能性が飛躍的に高まります。

例えば、Dockerは確かに便利でしょうし、世の中のイケてる企業やサービスはきっと使っているかもしれませんが、それが本当に自分たちの扱うサービスにとって適切であり、正しく使いこなせるのかは誰にも分かりません。従って、**そのサービスの根幹の技術であればあるほど、使いこなせるのかを必ず肌で感じた方がよい**です。

### 使えることと運用できることは違う

ただ、検証といっても、ちょっとだけ使ってみて、おお動く動く、これなら良さそうだと思って使うことと、本当にサービスにとって長く使えるものを使うことは違います。長く運用しないと露見しないトラブルなんて山のようにあります。それを最初から見通すなんて無理です。運用している間にbugのissueが上がってくることだってザラにあります。

従って、検証で何を確認して、どうであればパスするのかという判断基準は、最初に記載した「要件」をもとに決めてから検証を行いましょう。

# 結果的にどのようなポイントにハマったのか

上記を偉そう語っていますが、実際のところどうなったのかを紹介しておきます。

## 非機能要件の軽視

往々にして、サービス立ち上げで重視されるのは、どうしても機能要件だったりします。
その一方で軽視されるのが非機能要件で、サービスの継続性のためには軽視してはならないはずだったのに、机上での確認だけで済ませてしまっていました。例えば、HA構成を取ることができるのかとか、データのバックアップは無停止(オンライン)で可能なのかとか、そういった辺りです。

## プロダクト同士の組み合わせでの検証不備

とはいえ、実はそのプロダクトに関してのHA構成とかバックアップの可能性は、ちゃんと確認していました。ただ、「AとBを組み合わせればできる」という机上の想像に過ぎませんでした。
当然ながら、組み合わせでの実証は世の中に知見があるわけではなく、「普通できるだろう」と思って見過ごしていたら、いざ開発の後半になってテストしてみたら動かなかった…ということがありました。

**プロダクト単体での有効性は確認できていたししていたものの、組み合わせによっての実績があるわけではなかった**ところに問題がありました。

世の中にはいろいろと知見がありますが、**自分たちが行いたい環境と全く同じ条件での知見があるかはかなり怪しい**ので、ちゃんと検証を行うべきでした。例えば、インフラがオンプレかAWSかの違いがあるだけで動かなかったり、データストアがローカルディスクかNFSであるかだけで動かなかったりするかもしれません(実際、そういう違いでした。結果的には解消させましたが)。

## 実現イメージの曖昧さ

「ざっくりいうと」あれとこれで実現できる、ということは割と簡単に決められましたが、蓋を開けてみるとあの機能のためにはこれが足りない、この機能のためにはあれがないと実現できない、となって、結果的にこのプロダクトを選定したのは正しかったのか？となりました。

全ての機能と実現要素を最初に洗い出すのは至難の業ですが、それが具体的にイメージできればできるほど後々楽になるので、**最初に考えるのを諦めずに、時間の許す限りイメージを具体化しておいたほうがよい**です。

# 技術とプロダクト選定を終えて

サービスの立ち上げ時期に、技術とプロダクトを選定し終えたからと言って終わりではありません。そのサービスを長く続けたい場合、正しく成長するように、次のタネを植えておきましょう。

## 定期的に振り返る

選択した当初はベストの選択肢でも、時間が経つにつれて陳腐化したり、もっとよい解決策が生まれていることがあります。一度決めたものを二度と変更してはならないという制約があるならともかく、アンテナは高く持っておきましょう。

## 選定基準を残しておく

メンバが移り変わったときに、「なんでこの技術/プロダクトなの？」という話は絶対に出てきます。
小規模なサービスならともかく、大規模になればなるほどそうした知見が残っておらず、結果的にこの選択を変更してよいのかどうかが分からず詰むことになります(あるいは、調査のために多大な時間を消費することになります)。初期メンバーは、必ず「**何を考えて何を考えずに決めたのか**」を残しておいた方が、次世代の人々に石を投げられずに済むかなと思います。

* どんな要件があったのか？
* 何を絶対に守らなければならなかったのか？
* 逆に、どこは自由に変えてよかったのか？
* そのプロダクトを選定した決め手はなんだったのか？

# 終わりに

技術とプロダクトなんて壮大な話ですが、結果的には成功も失敗も踏まえて、経験してよかったなと思います。どちらかというと「べからず」的に書いてしまいましたが、うまくハマれば、**そのサービスを大きく飛躍させる原動力**にもなりえます。こうした知見を元に、サービスをうまく発展させていけたらなと思っています。