雀巽の日記帳

雀巽が綴る日常の記録

新規サービスを6ヶ月開発してみての感想、主に品質、技術的負債、開発スピードについて

スピード重視の方々が「今はテストは不要」とか「今はリファクタリングせずに負債を抱えるべき」とか、 そういったことを主張している場面によく遭遇してきたのですが、開発初期段階に対する経験不足が原因で、 それに対する自分の意見を自信を持って主張するということがこれまではできませんでした。

しかし、今年に入ってから6ヶ月間、主に1人(+デザイナーさん1人)で新規サービスの開発を行ってきました。

その結果、開発初期段階における品質、技術的負債、開発スピードのバランスについて、 色々と自分の中に考えができてきたので、それを書きたいと思います。

前提

ちょっとした前提ですが、自分が思う良いソフトウェアというのは「要求仕様通りに動作して、なおかつ変更しやすいソフトウェア」といったものです。

そのため、基本的には品質が悪い場合、開発スピードは落ちると思います。

たまに「品質を捨ててスピードを重視する」と聞きますが、これはその場でその機能を実装する瞬間だけの超短期的な話であり、 今後そこに何か変更していくという段階になった時に、確実にスピードを奪います。

それなのになぜこの話が話題になるかと言いますと 「新規事業では生き残ることが大事であり、今後そこに対して変更を加えるかどうかが不確かである」 というのが原因だと思います。

結論

変更はすぐにどんなものに対してもやってきます。

そこで、やはり初期段階から常に変更を見据えて進めるべきです。 ただし、力の入れどころ、抜きどころは確実に存在していると思います。

話題になることが多いリファクタリングとテスト、それと個人的に重要だと思ったデータベースに関して、それぞれやるべきだと思ったことを紹介します。

  • 初期段階でデータベース設計を徹底的に行う
  • リファクタリングは常に作業の一環として行い設計とコードを綺麗に保つ
  • テストは事業継続上絶対に落とせない箇所だけは最低書く

それぞれ、なぜそう思ったかを書いていきますが、まずはサービスの状況を背景として説明しておきます。

背景(サービスの状況)

  • エンジニアは主に1人(7月上旬時点)
  • 開発開始は2016年1月中旬
  • リリースは2016年2月末
  • 2016年の業績次第では撤退も十分ありえる
    • 撤退してしまえば当然全ては水の泡

では、先ほどの結論を順番に説明していきます。

初期段階でデータベース設計を徹底的に行う

追加や変更に強いデータベースを初期段階で設計しておくべきだと思いました*1。 Web サービス系の会社ではドキュメントが軽視されがちですが、ERD は絶対あったほうが良いです。

ERD があるのとないのでは、機能の追加/変更時の設計コストがまるで違います。 ERD の保守コストよりもリターンのほうが確実に大きいと感じました。 ちなみに ERD は概念設計のみを保持しています。論理/物理設計は Railsマイグレーションファイルと内容が重複し、かつ簡単にリバースエンジニアリングできるため管理していません。

主な理由は、

  • データベースは経営資産であり、ERD はビジネスの写像である
  • データベースはアプリケーションの根幹であり、ここが破綻していると全てが破綻すると言っても過言ではない
    • 逆にデータベース設計がしっかりしていると、かなりコーディングがしやすく開発スピードがあがる
  • データベースは基本的にリファクタリングが難しく、スタート段階で設計がコケていると立ち直しが非常に難しい
  • 新規事業では要件や機能の追加、変更が非常に多く、データベース設計が頻繁に変更される

です。

コーディング速度、変更時の対応コストを考えると、最初に時間をとってデータベース設計をみっちりすべきだと思います。

また、アプリケーションコードでは「要るか要らないか迷ったら YAGNI に従いとりあえず作らない」が大抵の場合正解になりますが、 データベースの場合は「迷ったらとりあえず作る(詳細にしておく)」というのが良いと思います。

というのも、データを統合するのは比較的簡単ですが、分割するのは難しいからです。

リファクタリングは常に作業の一環として行い設計とコードを綺麗に保つ

リファクタリングというのはそもそも、日々の作業の一環として行うべきものというのは問題ないかと思います。

アプリケーションの変更は常に発生し、その変更に対応していくためには適宜その時々で最適な設計に変えていく必要があるからです。

ここでは「完璧」ではなく「最適」というのが重要です。 完璧にするのはそもそも不可能だと思いますし、目指すことそのものにコストが掛かり過ぎます。

そのため、その時点での「最適」は何か、つまり現時点ではどの程度の品質を目指し、どんな負債を受け入れ、将来的にはどう対応していくかということを常に見極めていく必要もあります。

やり方としては、基本的には何かの作業に合わせて「周りのお掃除」的な感じでリファクタリングをするのが良いと思っています。 「リファクタリング中に機能追加をするな、逆もまた然り」といいますが、それはプログラミング中の話なので、 タスクレベルで考えると「機能追加前に設計をブラッシュアップし、そこに機能追加していく」という流れは全然問題ないと思います。

それで、なぜこの当然の話を持ち出しているかと言いますと、 「そもそもリファクタリングを日々の作業としてやるという考えがない人」や 「その機能は今後変更されないと言って汚いままひたすら追記を繰り返す人」が リファクタリングは必要ないと主張してくることがあるからです。

リファクタリングを何のために何故どのタイミングでやるかに対しては、以下の本を読んでください状態*2なので今回の範囲外とします。

新装版 リファクタリング―既存のコードを安全に改善する― (OBJECT TECHNOLOGY SERIES)

新装版 リファクタリング―既存のコードを安全に改善する― (OBJECT TECHNOLOGY SERIES)

リファクタリング:Rubyエディション

リファクタリング:Rubyエディション

ここで言いたいのは「リファクタリングは新規サービスでも日々の作業としてやるべき」ということです。

その根拠ですが、半年間開発してみて、リリース後に変更しなかった機能が一切存在しないというのが最も大きいです。

データベースの項でも述べましたが、新規事業では要件や機能の追加、変更が本当に多いです。 ここで設計の見直しやリファクタリングをせず、とりあえずのコードを追記し続けると即破綻します。

破綻とまでは行かなくとも、すぐに書いた本人もなにしてるかわからないコードが量産されます。

たった数ヶ月の開発でそんな複雑にならないでしょと思う人もいるようですが、数時間あれば動く暗号は書けます。

テストは事業継続上絶対に落とせない箇所だけは最低書く

余裕があれば当然可能なかぎり書くべきですが、事業継続上絶対に落とせない箇所を最低カバーしてれば問題ないかなと思いました。

流石に最低レベルのカバー率だと色々困ることも多いので、現段階ではユニットレベルのテストは全て書いています。 ただ、E2E テストは一部の機能でしか書いていません。

理由としては、

  • 複雑な機能が少なく、短時間の手動テストで大部分がカバーできる
  • 変更が非常に多く、特に E2E テストの変更が多発する
  • 多少サービスの一部機能が落ちたところで大きな問題が起きるフェーズじゃない

と言ったところです。

もちらん、あるに越したことはないですが、ホントに大事なとこ以外はなくても何とかなります。

ただ、動作確認自体に手間がかかるようになってきた場合は、今後のことを考える即テストを書くべきだと思います。 そういった機能については、積極的にテストを拡充していくようにしています。

また、その時点でうまく設計できなかった箇所や、可読性が低くなってしまった部分にも、 未来の自分を助けるためにテストを書いておいたほうが良いかもしれません。

まとめ

  • 初期段階でデータベース設計を徹底的に行う
    • やや手間も時間もかかるが、短期的にも長期的にも得られるリターンがかなり大きい
  • リファクタリングは常に作業の一環として行い設計とコードを綺麗に保つ
    • 変更は全機能で発生する可能性があり、難解な設計や難読コードは早ければその日のうちに自分の時間を奪いに来る
  • テストは事業継続上絶対に落とせない箇所だけは最低書く
    • 手動テストを繰り返す時間的コストや、機能の重要度と相談し、リターンの方が大きい物は書く

スピードを維持し続けるのに大切なのは「設計」と「継続的改善」だと感じました。

最低限のテストで大量の変更を乗り切るためにも、拡張しやすい設計と読みやすいコードを維持し続ける必要があると思います。

補足

テストの伴わないリファクタリングはコード破壊やエンバグ作業とも言われますが、手動テストでカバーしてたり、機能自体が仮に落ちても業務上の損失があまりないのであれば、やっちゃって良いんじゃないかなと思ってます。

特に、新規事業は「数ヶ月後にそのサービスがあるかないかわからない」といったステージですので、それを判断軸に色々大胆に行っていけば良いと思います。

感想

ソフトウェア開発において常に発生する唯一のものは「変更」というありがたいお言葉が結局のところ全て。

*1:ちなみにオススメはイミュータブルデータモデルです

*2:私は Ruby エディションしか読んでいません