4月から、新たに3名のエンジニアがCureAppに加わります! 今まで、チームとしてどうあるべきか、というのもあまり考えずに走ってきました。 ということで、ここで一度振り返って、どういうチームでありたいか、ということをまとめてみました。
長くて暑苦しくなってしまうものですね。 これを、初版としてどんどん改良していきます。
CureApp開発チームの目指すもの、それは
それぞれが別な得意領域を持ちながら広くシステムを理解し、開発に参加できるチーム
社員は、どのプロジェクトにアサインされても戦力になるようにする。
そのために、
- マルチプラットフォームな言語を選択する (まずはJavaScript)
- 皆が思う「良いコード」が同じになるように、設計思想を統一。
- 同期/非同期コミュニケーションにより情報を共有。
- 確かな方法で技術選定し、優れた技術を共通して使う。
- 全システムを俯瞰できるよう、専門領域(ドメイン)への理解を深める。
- 複雑な手順を自動化する。
マルチプラットフォームな言語を選択する
言語の統一は、 - コードの共有 - 習熟スピードの速さ - 思考切替えのスムーズさ
に理がある。 なんといってもプラットフォーム間でのビジネスロジックの共有という 究極のDRY (Don't Repeat Yourself)が実現可能だ。
なぜJavaScriptか ~言語の比較~
マルチプラットフォームに利用できる言語を独断で比較してみた。
言語 | プラットフォーム多様度 | 人気 | 将来性 | ライブラリの充実 | 手軽さ | 堅牢性 |
---|---|---|---|---|---|---|
JavaScript | ◎ | ◎ | ◎ | ◎ | ◎ | × →▲ |
Java | ◯ | ◎ | ▲ | ◎ | ▲ | ◎ |
Swift | ▲ | ▲ | ◎ | ▲ | ◯ | ◎ |
C# | ◯ | ◯ | ◯ | ◯ | ▲ | ◎ |
利点
なんといっても近年のマルチプラットフォームといえばJavaScriptの存在が際立つ。 Webブラウザ、Node.jsはもちろん、「ハイブリッド」型のスマートフォンアプリ開発(Titanium, React Native, PhoneGapなど)、またElectron、Google App Scriptなど、JavaScriptで開発できないプラットフォームはほとんどない状態だ。 そしてそれがまた人気を加速させる。ES2015の登場など、まだまだ言語として 進化を続け、将来性もある。優れたJavaScriptのエコシステムであるnpmはここ5,6年で爆発的に普及した。 背景にはJavaScriptの手軽さ、柔軟さがあるだろう。
克服可能な、欠点
JavaScriptの唯一(しかし無視できないほど大きい)欠点。 それは言語そのものに堅牢性が備わっていない、"柔軟すぎる"ということだ。 だが近年はクラスの登場、モジュールの仕組みの統一などで 大規模開発に対応できる言語として進化を遂げた。 もともとの手軽さ、スピード感を利用しながら、 チームとして設計思想を揃えることで堅牢なJavaScriptを目指す。
Swiftの可能性
iOSアプリをネイティブサポートするオープンソースの言語、Swiftは、 Linuxでも実行可能となった。 2010年代のモダンな思想からくるOOPと関数型のハイブリッドのような 柔軟かつ堅牢な言語は、将来的な選択肢となる可能性はある。 注目を続ける。
設計思想を統一する
原則としては以下の3つだ。
- プログラムの分け方に関する共通理解を持て
- テストは将来のためにするものだ
- 変数名、ディレクトリ構成、コーディングスタイルに、理由を持て
分け方 = 適切なインターフェイスの設定
モジュール、ファイル、クラス、メソッドなど、すべては切り分けられ、 その切り分け方こそが設計の真髄と考えている。
分けたときに、分かれた2つの間の情報のやりとりが「インターフェイス」である。 分け方を決めることは、インターフェイスを決めることと等しい。
つまりインターフェイスを決める事が設計の真髄である。
分け方に関しての絶対的な正解はないが、メンバー同士で分ける感覚を揃えたい。 よって、下記に私の分け方のポリシーをいくつか記した。
汎用モジュールの分離
CureAppのサービスとしては汎用的すぎる実装だ、と思ったらそこを汎用的なモジュールとする。 例えばbase-domainは、モデルの生成や取得に関わる基本的なロジックを担う。
ビジネスロジックの分離
アプリ、ビジネスロジック、インフラ の3層を正しく分離すること。 ビジネスロジックは、
- 表示形態に依存しない
- インフラの構造に依存しない(Repositoryはその橋渡しとして限局的に依存あり)
- 非エンジニアでも理解可能
ものだ。
外部のインターフェイスに依存する層を限定する
たとえばCureAppのサービスはLoopBackという外部モジュールに依存しているが、 「LoopBackならではのAPI」はドメイン層に限定している。 さらにdomainのなかでもRepositoryに限定している。 これによって、 - LoopBackがおかしい - LoopBackをやめたい
といったときに、修正範囲を限定的にすることができる。
privateとpublicは明確に。
publicなものが「インターフェイス」だ。 また、誰に対してpublicか、例えば Javaでいう"packageレベルのアクセス制限" も必要だ。 例えば「domainというモジュール内部では使用されるAPIだが、 外部からは呼び出されるべきではない」というAPIもある。
JavaScriptにアクセス修飾子がないのは致命的な欠陥だが、 自動ドキュメントでカバーすることを徹底する。
データとロジックの分離
データを増やし、ロジックを減らす。 なぜなら、ロジックにはバグがあるが、データにはバグがないからだ。
ユニットテスト
テストは、仕様変更の際の動作保証にもなる。
仕様にこそテストを書け
仕様 ≒ インターフェイス 外からどう見えているか。
"こう使われると、こうなる"ことの証明なのだ。
private methodのテストは、カバレッジのために必要なら書く
privateなメソッドは、検証したい一方で、
が発生するため、慎重に。
domesticなサービスのレポジトリのテストは積極的に日本語で書いていけ
日本語で書くことで、非エンジニアにも仕様がわかる。
it('PM 3:00にpush通知が配信される', ()=>
これでいい。
コミュニケーション
- CTOは、情報共有のための時間をつくれ!
- メンバーは、CTOの情報共有を促し、遠慮するのは義務違反と思え!
- 情報共有は1:1でせず、皆が見えるところでしろ!
情報共有は、現実の会話やチャットなどの同期的なものと、 issue、コメント、ドキュメントなどの非同期的なものがある。
同期的コミュニケーション
会話やチャットのこと。
とにかく、遠慮しないことが大事! 受ける側は、相手が必要と思っているのだから、快く情報を共有する。 そして、そのサマリを非同期コミュニケーションツールに反映してほしい。 他の誰かも必要と思っている可能性が高いから。
非同期的コミュニケーション
- github issues (waffle.io連携) に作業内容を共有
- Qiita:TeamやDocBaseなどの社内情報共有ツールに日報やハマりどころを書く
- READMEなどのドキュメントを書く
- ソースコードにコメントを書く
- Google DriveやCacooなどに資料的な情報を書く
これらが、非同期的コミュニケーションだ。 場合によってはチャットツールも非同期的コミュニケーションといえる。
大事なのは、 これらは決して特殊業務ではないよということだ。
コーディングしながらコメント書いて、 README更新して、 ハマりどころをDocBaseに共有して、 Google Drive上のスプレッドシートを更新して、 一日の終りに日報を書く。
これが、一連の業務だという認識を持てば、 非同期的コミュニケーションが活性化され、情報の局在化が防げる。
技術選定
汎用的なツール、モジュールの使用は、各プロジェクトで統一する。 そのほうが、理解が速い。
悪い例
- プロジェクトAではtestにvowsを使っている
- 僕は主にプロジェクトBでmochaを使っている
- テストの書き方違うのか、調べないと...。
技術選定する上でのポイント
前提として、github上にあるものを利用する。
上から順に大事。
- 地雷が踏まれているか。(スター数、Web上の露出、issue)
- APIの筋の良さ。 特に、シンプルさ。
- メンテナが多いか
- 一般的な(少なくともEarly Adapterの)開発者に馴染みがあるか
- 実績
- ライブラリ自体のメンテナンサビリティ (≒実装のよさ)
JavaScriptで採用すべき技術
以下はざっくり思いついたものを挙げた。(2016年3月時点)
- Node.js
- npm
- babel
- browserify
- gulp
- Promise
- WHATWG Streams
- mocha
- power-assert
- React.js
- moment
技術の移行
とはいえ、採用した技術が"腐る"ことはある。 その場合は、技術を移行していく必要がある。 ただ、すでに動いているものを置き換える作業は、 事業としての優先度が高くないことを自覚するべきだ。
移行のための良いパターンは、
- 新しい技術に移行した記事などをあさり、ベストプラクティスを探る
- 新しいプロジェクトで導入して、ハマってから移行する
情報を収集する、試す
ブログやtwitter、facebookなどのメディアを活用することで、 情報を集めることができる。 さらに気になった技術を試せば、より感触がつかめるだろう。
個人的には、その活動は、業務時間に意図してやらなくてもよいと考えているが、 禁止するわけでもない。有用な情報があれば社内で共有していく。
業務時間にどこまでやるの?
「CureAppの業務」とはなんだろう。 上記のような情報収集や新技術を試す部分なども業務と解釈すると、 経営陣は短期的には苦しい一方で、長期的には良い投資にもなりうる。
よって、CureAppは、経営的な観点から、業務時間外に趣味で情報収集したり 新技術を試したりしてくれる人材を優先的に確保する。
監視するのは誰の得にもならない。 「よいプロダクト、よいサービスをつくる」という共通の方向を 向いて、自己判断する。 そのうえで価値観が経営陣と合わなければ、 そこはすり合わせていくことになるだろう。
自社製OSS
- CureAppとして必要
- 汎用化できる
- 既存のライブラリで適切なものがない
という場合には、自社でのライブラリ開発も推奨される。 この活動は、CureAppが技術力を持った会社であるというイメージ向上にも繋がる。 慣れも必要だが、CTOにノウハウがあるので聞いて欲しい。
専門領域(ドメイン)への理解
- 変数名や日本語は意外に大事。表をつくれ。ユビキタス言語で会話できるように。
- 鈴木が医療知識との架け橋になるので、迷ったら必ず相談する。
- ドメイン専門家と話したり本を読んだりして、ドメイン知識をつける。
通常業務として知識をいれてくれ、というわけではないが、
- 疑問を持つ
- わからなければ鈴木がいるから活用する
- よりよいプロダクトになるよう、提案する
といったことが肝要だ。 特にプロダクトへの提案は歓迎だ。 医学的な視点だけでなく、UX的な視点で提案することで、 バランスのとれたプロダクトに近づくことができる。
自動化
開発の自動化
業務のうち、コーディング以外の部分で、 煩雑な手順を伴う作業はいくつも存在する。
- コンパイル、
- デプロイ、リリース
- テスト
- ドキュメント
npm scriptsやgulp、gruntなどがかなりの部分を自動化できる。 リリース作業に関しては、CureApp製のOSSである node-circleci-autoreleaseを利用する。
各プロジェクトでの手順を統一するとよい。
運用の自動化
CureAppがCureAppたるのは、インフラにおいてではなく、 そのサービス、プロダクトにおいてである。 インフラに関しては、良い技術選定の上で、 自動化できるものを選んでいくとよい。
REST APIの自動化:LoopBack インスタンス生成の自動化、簡素化:Heroku、Engine Yardなど アプリケーション層のスケール自動化:AWS Lambdaなど DB層のスケール自動化:DynamoDB, mLabなど
もう一度
CureApp開発チームは、それぞれが別な得意領域を持ちながら広くシステムを理解し、開発に参加できる、というものを目指している。
そのために、 - マルチプラットフォームな言語を選択 - 設計思想を統一 - コミュニケーション - よい技術選定 - 専門領域への理解 - 自動化
を実践する。