PMFを狙うスタートアップの開発戦略

オンラインヨガサービス『SOELU』を開発している Kohei Kataoka です。副業としてSOELUサービスローンチまでの開発をほぼ一人で行い、現在は取締役CTOとして開発を指揮しています。


この投稿では、私たちがSOELUをプロダクトマーケットフィット(以下、PMF)させるべく行ってきた開発戦略を、スタートアップにおける開発の一例としてアウトプットします。スタートアップでWebサービスの開発を行っている方の参考になれば幸いです。


PMFを目的とした開発で重要なこと

PMFを目指す中で開発チームに求められるのは『素早くアイディアを世に出し検証サイクルを回す』ことに尽きます。それを実践するために、以下のことに注力して開発を進めています。

  • 最短でサービスをローンチする
  • 素早く変更を行う
  • 持続可能性を保ち続ける

最短でサービスをローンチする

サービスが世に出ない限り、検証は何も始まりません。最短でサービスをローンチするための技術選定を行う必要があります。

技術的な冒険はしない

重要なのは『チームをリードできる技術を使うこと』であると考えています。最も自分が精通している技術で、メンバーが躓くことなく一直線に開発できるようサポートする必要があります。私の場合、最も手に馴染んだ言語がRubyであったため、Rubyを選択しました。

コードを書かないことに勝る手段はない

また、『いかにしてコードを書かずに済ますか』という観点も重要です。成熟したフルスタックフレームワークを使用することで、自分たちで書くコード量は圧倒的に短縮できます。私たちの場合、Ruby on Railsを使うことで多くの処理をGemに丸投げし、管理画面はRailsAdminを使用することで開発時間を圧縮しました。Railsはもちろん銀の弾丸ではなく問題点もありますし、エンジニアが自ら設計する余地が少ないという点でエキサイティングな選択肢でもありません。しかし、Webサービスに求められる機能を素早く実現するという点で優れた選択肢だと思います。

複雑なデータモデルは避ける

ローンチ後サービスがどのような拡張をしていくか読みづらい部分は、なるべくシンプルなモデリングで済ますように心がけました。データモデルの設計はシステムの根幹になるので手抜きは厳禁ですが、複雑なデータモデルを扱うためには、コードも複雑にならざるを得ません。また、プロダクトの初期はイレギュラーの連続のため、エンジニアではない人でもモデルを理解しプロダクションのデータに変更を加える必要があったりします。そのような事情から、あえて正規化を行わなかったり、拡張性は低いがシンプルなモデルをあえて選んだ場面がいくつかありました。サービスローンチから1年経過したいま、問題になりはじめた箇所から再度モデリングを行っています。ローンチ時よりもドメインモデルがクリアになっている分、より正確なモデリングが行えています。


素早く変更を行う

プロダクトをローンチしたあとは、ユーザの反応を見ながら動線を改善したり機能を追加したりしていきます。限られた資金と時間の中でPMFを探っていくため、ここでも開発速度は最優先事項です。

速度重視で開発するために色んなものを削ぎ落としていくわけですが、この章では「これは削るべきではなかった」と反省している事柄を紹介します。

テンプレートエンジンを避ける

WebサービスのUIは年々リッチになっていて、ユーザの期待値は高くなっていますし、プロダクトオーナーやデザイナーが考えるUIも複雑な実装を伴うものに変化しています。かつてモバイルアプリでのみ実装されていたようなインタラクティブなUIがWebでも求められています。

私たちはhamlとscssを使ってビューを構築していたのですが、これは早々に破綻しました。jQueryによるDOM操作でリッチなUIを実現するのに無理が生じていたという問題が1つ。もうひとつは、hamlもscssも管理するのがとても大変だということです。色んなところでツラミは共有されているのでここはあまり深掘りしません。関連するTweetと社内ドキュメントの引用をしておきます。

私の意見では、Reactがテンプレートエンジンに比べて優れているのは、入力される値がわかりやすくできるということ、そして、本来それぞれが一体となってはじめて役割をなす「構造(html)」「装飾(style)」「振る舞い(js)」が1セットで管理できる(あるいは極めて近距離にソースコードを配置できる)ことによる、関連物をさがす煩わしさからの解放、改修漏れ削除漏れからの解放、そして論理的にしっくりきてる感かなと。

元々、デザイナーやWebフロントに疎いメンバーでもビューのコードが書けるようにhamlとscssというRailsアプリケーションとしてはメジャーな選択肢を取りましたが、いま振り返ってみると最初からReactで書いておけばよかったな、という反省があります。

現在は新しい画面からReact化しています。JSによるインタラクションの有無に関係なく、単なるマークアップとしてもReactで作られた画面のほうが改修しやすいです。エンジニアのメンバーに関してはReactのキャッチアップをしてもらい特に問題なくすんなり受け入れられていますし、デザイナーとは完全分業化してマークアップはお任せしない方針にしています。CSSもstyled-componentsを使用することで、BEMをはじめとしたCSS設計論に触れることなく独立したスタイルを保てています。

コスパの良いテストを書く

テストを一切書くことなくサービスローンチまで開発を進めましたが、変更を加える中でくだらない理由でデグることが多くなっていきました。特にRubyだと構文さえ通ってしまえば実際に実行されるまでバグに気づきづらいため、安心してリリースしていくためにレグレッションテストはあったほうがいいなと思うようになりました。

しかし、アプリケーションのあらゆる箇所がすぐに変更される状態ですから、あまり重厚なテストを書いてもメンテナンスが大変です。そこで、以下のルールに従って最低限のコスパのいいテストを書く方針に決めました。

  • 最低限Request Specは書く
  • 各テストはステータスコードを確認するくらいで十分

つまり、以下のような簡単なテストコードを書いていきます。(Request Specと書きましたが、よりシンプルにテストを書くためにRSpecではなくMiniTestを使用しています)

これは極端に短い例ですが、これだけでも用意しておくと、バグに気づきやすくなります。Railsプログラミングで起きる例外の大半はnilに対するNoMethodErrorですしね。

ベストではない実装を受け入れる

スタートアップとはいえコードの品質に無関心でいられるわけではありません。各リポジトリごとにテックリードを配置し、コードの健全化を図るようにしています。

スタートアップではiOSエンジニアでもRailsを触らなければいけないことも多いし、その逆もまた然りです。門外漢な分野に挑戦するとき、必ずしもベストな実装を行えるとは限りません。そのような状況下で、ベストな実装以外受け付けないというテックリードの姿勢だと、なかなか開発が進みません。メンバーの成長を促しつつ、妥協点を決めてコードレビューをしていく必要があります。

その妥協点を決めるために、私は以下のような方針を立てました。

  • 挙動に問題がなければちょっとした問題点には目をつぶる
  • 妥協したコードには必ずFIXMEのコメントを書いてもらう
  • FIXMEが書かれた箇所を修正するときはまずリファクタリングする
挙動に問題がなければちょっとした問題点には目をつぶる

技術的負債というのは、変更が必要になったタイミングで問題が顕在化するもので、変更を加えない限りはうまく動き続けます。もし、その後変更することがあまりないコードであれば「正しい実装」である必要性は薄いかもしれません。また、あらゆる施策を試す中で頑張って実装したコードをrevertすることもザラにあります。

※変更する前から問題が起きているものは技術的負債ではなくバグなのですぐ直します
※パフォーマンス問題などは変更云々に関係ない技術的負債と言えますが、ここでは一旦別の問題とさせてください

妥協したコードには必ずFIXMEのコメントを書いてもらう

既存コードを参考にして新しいコードが書かれることがよくあります。妥協したコードを真似してよくない実装が蔓延することを防ぐために、妥協する場合にはFIXMEのコメントを残すようにしています。

FIXMEが書かれた箇所を修正するときはまずリファクタリングする

修正が必要になったということは、その機能の寿命が長く、頻繁に変更される可能性があるということです。ボーイスカウト精神に乗っ取り、「来たときよりも綺麗にして帰る」ことを心がけています。ここでよくない実装に更によくない実装を重ねるようになると、どんどん修正が難しい負債化したコードになっていってしまいます。


持続可能性を保ち続ける

当然のことながら、成功を信じてプロダクトを改善し続けるわけですので、PMFして、アプリケーションがより長い寿命を得たときのことも考える必要があります。

simpleよりeasyを優先しなるべくコードを書かずにフレームワークに頼っていた状態から、徐々に自分たちのユースケースに沿ったspecificでsimpleな実装に置き換えていくべきタイミングが来ます。チームの拡大にあわせてマイクロサービス化を進めていくという選択肢もありそうです。

私たちの場合、そのようなサイドプロジェクトをGoで実装しています。Goを選択した理由は以下の通りです。

  • スクリプト言語に劣らない気軽さで高速に動作するコードが書ける
  • 構文の学習コストが少なく、人によって実装のブレが生じづらい
  • コンパイル時にある程度エラーが検出できる
  • 多くの機能が標準ライブラリとして提供されており、過度に抽象化されていないため、自分たちのユースケースに合わせて開発できる
  • 自分たちでアーキテクチャを考える余地が大きいため、フレームワークを使ったプログラミングからキャリアをはじめたメンバーの学習機会になる

おわりに

オンラインヨガサービス『SOELU』をPMFさせるべく1年間開発してきた中で学んだ開発戦略を、スタートアップにおける開発の一例として紹介しました。

現在はWebアプリケーションの開発だけでなく、リッチなネイティブアプリの開発やWebRTCを使った独自の動画配信システムの構築に開発の軸足をずらしてプロダクトを進化させています。

また、直近ではGraphQLとReactNativeをプロダクションに投入するなど、枯れていない技術でも必要に応じて積極的に使うことに挑戦しています。

エンジニアとデザイナーを積極採用中ですので、私たちのプロダクトに興味がある方はぜひ以下のTwitter宛にご連絡ください。

使用している主な技術

  • Ruby on Rails
  • Kubernetes(GKE)
  • React/Redux
  • ReactNative
  • GraphQL
  • Go