CTOとしてスタートアップに転職して9ヶ月で学んだこと(技術編)
こんにちは。株式会社NoSchoolでCTO(最高技術責任者)を務めている名人です。
2019年3月に前職のLIFULLからNoSchoolに転職して9ヶ月が経ちました。年末なので、自身の振り返りをまとめていこうと思います。
会社としては勉強質問サイト/アプリを運営していまして、普段働いているのは社長と僕と週5の業務委託の3人。超が付くほどのドベンチャーで生きるか死ぬかの闘いを続けています。
技術編に続いて、Redashで数値分析編も書いていますので、よかったらそちらも読んでください!!
技術編・目次
第1位 ドメイン駆動設計
第2位 フロントエンド
第3位 月額課金の実装
それではさっそくまとめていきます。
第1位 ドメイン駆動設計
栄えある第1位はドメイン駆動設計です。
ドメイン駆動設計という言葉を僕なりに定義させていただくと、
これまで多数派だった、エンジニアが技術的な観点を持ち込んで設計・開発していた手法に対し、サービスが提供する価値や領域(≒ドメイン)を中心に据えて開発する手法
のことです。
技術的な観点というのは、データベースにどのような形式でデータを保存しよう?であったりとか、今使っているフレームワークがRailsだから、Railsらしい開発をしようというような、エンジニア視点のことを指します。
技術のプロであればあるほど、ついついそこから思考を始めてしまうのですが、ドメイン駆動設計を実践するにあたっては、まずはサービスが扱うモノや提供価値を、エンジニアじゃなくてもわかるような言語で徹底的に落とし込むところから始めます。
そして、あくまで落とし込んだ言語をそのまま表記するかのように実装していくのがドメイン駆動設計の手法です。
実世界において、エンジニア都合でサービスが動くことはほとんど無く、9割方はサービスの都合、現実世界の都合で仕様が変わり、サービスが成長していきます。
つまり、技術的な観点で設計し、実装されたものであるほど、あとから現実世界の都合に振り回されやすいシステムになってしまうと言えます。
ドメイン駆動設計のアプローチでは、あくまで現実世界のモノを徹底的に文章に落とし込んでから、その文章を実現するように実装することを心がけます。
ことスタートアップにおいては、PMF(ビジネスモデルが想定市場にピッタリ合っている状態)が実現するまでは次々とサービスが変わっていきますので、設計に時間をかけるというよりは、RailsやLaravelといったWebフレームワークに則って速度優先で実装していくことがほとんどでしょう。
僕も、ドメイン駆動設計を学んで実践してみたものの、サービスの実装すべてをドメイン駆動設計に変えていくことは到底間に合っていません。
しかし、たとえ少しでも学んで実践したことで、自分たちが速度優先で開発しているものが、どのような爆弾を抱えていて、限られた時間の中でもどういったことに気をつけて実装すれば少しでも技術的な負債を残さずに開発を進めていけるのか、というのが見えてきた気がします。
その意味で、「スタートアップなんだから速度優先!設計は多少妥協して突き進もう」という考え方から「速度と設計がトレードオフになっているのは自分に実力がないから。本当は速度を保ちながら変更に強い設計にすることがきっと可能なはず」という考え方にシフトできたことが大きいと思っています。
Qiitaに詳しい実装などは載せていますので、興味を持ったエンジニアの方はぜひ。
第2位 フロントエンド
NoSchoolではフロントエンドにNuxt.jsを採用しています。
Nuxt.jsというのはここ数年台頭してきたJavaScriptのフレームワークであるVue.jsをさらに定型化したフレームワークです。そのためNuxtは俗にフレームワーク・オン・フレームワークと呼ばれることもあります。
僕の前職ではフロントエンドにjQueryを採用していたため、今回Nuxtを採用したのは僕にとってチャレンジングなことでした。
未経験なNuxt.jsを採用した理由は、ひとえに「開発スピードが上がるから」です。
端的に言えば、特に、1つのページの中で表示がちょくちょく変わるような場面で開発スピードが段違いになります。具体的にいうと、noteを投稿するときに最後にタグを選ぶわけですが、タグを選ぶときに文字を入力すると予測候補が表示されて、その中からタップするとタグが1つ増える、というような演出を実現するスピードが上がります。
別にjQueryでも実現はできますが、Nuxt(正確にはVue)のほうが、より低スキルなエンジニアがよりハイレベルな演出を容易に実現できるのです。
Nuxtを採用するメリット自体は他にも色々ありますが、この9ヶ月で一番事業的なメリットを享受できたのは開発スピードが上がり、機能の検証を次々開始できたことでしょう。
また、UIフレームワークとしてVuetifyを採用したことも開発スピードに大きく貢献しました。
とはいえデメリットも一方でたくさんあります。
・ページの初期表示が遅め(LightHouseスコア20〜50程度)
・エンジニア向きのため、デザイナーさんがコーディングに入れない
・Vuetifyを盛大に使ったので、Vuetifyのバージョンアップ時に多少作業が生じる
・APIの利用をどこからでもできるようにしたので、APIを変更したときの影響範囲が読みにくい
・SSRの運用コストが高い。サーバーもスペックが少し高めになるし、メモリリークでたまに落ちる
ただ、これらのほとんどはあくまで僕のNuxtの使いこなしが悪かったからであり、Nuxt自体のデメリットではないことを書き添えておきます(よくこの補足が無いせいでキツめのツッコミを受ける)。
そして、これらの問題には下記のような施策で現在立ち向かっています。
・バンドルサイズの解析をして、重めのライブラリのimport箇所を絞ったり、CSSのpreloadなど基礎的な対策を徹底
・TypeScriptを導入し、API利用はaspidaというライブラリ経由で行うことで影響範囲を絞る
また、もし僕が4月頃にタイムスリップしたら、下記のような方針で開発をするでしょう。
・初期からTypeScriptを入れて、特にAPIとSEO対策の実装を仕組み化する
・サーバーではなくLambdaを使う
・正直VuetifyではなくtailwindCSSのような軽量ライブラリを検討するかも。重たいライブラリは結局パフォーマンス改善が厳しい
(一応補足。Vuetifyはtree-shaking対応しているものの、結局あのボリュームのCSSをインライン展開すると初期表示でちらつくし、extractCSSはpreload未対応だし、あまりにもv-btnなど大量に利用しているとScript Evaluationに時間食います。なので、最初はサクッとVuetifyで作り、事業的に必要と固まったページから徐々にVuetifyを脱却していこうかと目論んでいるところです)
第3位 月額課金の実装
第3位は月額課金の実装です。
NoSchoolでは月額課金プランを実装しており、2019年12月にWebとiOSアプリでほぼ同時にリリースしました。
簡単に言うと、NoSchoolでは勉強質問サービスを運営していて、日々家庭教師の先生方が回答してくださっているのですが、他人の質問に回答した内容を見るときは月額課金しないといけないというものです。問題集別の質問も過去2年分蓄積されているので、パーソナライズしてその人が欲しい回答解説を配信する仕組みも作っています。
Web側ではPAY.jpを、アプリ側は普通にAppleが公式で用意しているIn App Purchaseで実装しています。
課金実装は本当に気にすることが多いですね。リリース後、致命的なバグは無いのでトラウマにならずに済みました。
・何かあった際にユーザーに連絡取れないと詰むため、メールアドレス検証が必須
・クレジットカード情報入力から決済処理成功、データベースへの決済履歴の保存まで全てトランザクション(ACID)で実現しないといけない
・定額課金の場合、1月ごとに決済ベンダーが更新処理をするが、そのWebhookハンドラも実装しないといけないし、テストもやりにくい
・アプリとWebが同時リリースなので、Webで課金したユーザーがアプリを開いたときとか、その逆とか、気にするパターンが増える
・定額課金の場合、キャンセルしても最後の支払いから1ヶ月経過するまでは有効なままになるので、そこの判定ロジックをどう上手く実装するか
などなどありますので、最初にお話したドメイン駆動設計のアプローチを大いに活用しました。ついつい決済の実装は決済の裏側を知っているからこそエンジニアの視点で作ってしまいがちですが、あくまでドメインに着目して実装することで、Webでの実装とアプリでの実装が両方共通化したり独自に実装したりのバランシングが少しは取れたかなと感じています。
iOSアプリの課金はレシートという文字列をアプリとWebサーバーでやり取りして行いますが、結構込み入った実装になるし例によってApple公式のドキュメントが雑なため迷います。もし迷った方はぜひ相談してください。
総括
技術の視点では、本当に2019年は色々なことに挑戦できました。
個人的には設計とテストが苦手分野だったので、そこに思い切り向き合わないといけない立場になったことで、多少は身についたかなと思っています。
CTOは事業の成長が自分の成長になる仕事なので、事業をしっかり伸ばしていけるように引き続き頑張ります!
日々技術書を始めとする書籍を買って読んでいます。書籍代にさせていただきますので、よかったらぜひサポートお願いします!