EC studio EC studio 技術ブログ

2012年04月23日投稿者:山本 正喜

チャットワーク開発の裏側

大変ご無沙汰な技術ブログ更新となってしまいました。
振り返ってみると、前回の記事がもう約2年前!
ブログ記事を楽しみにしていただいていた方には申し訳ない限りです。

この2年間、何をやってたかというと、
チャットワーク」というサービスの開発に全社を挙げて取り組んでいました。

チャットワークロゴ

チャットワークはおかげさまで2011年3月1日のリリース以来、
1年で6万ユーザーを突破し現在も順調に成長を続けています。

そして今年の4月1日に、創業から12年使用し続けてきた
「株式会社EC studio」という社名を「ChatWork株式会社」へと
変更することを発表しました
(※エイプリルフールに発表しましたが、本当です^^;
変更の実施は6月ごろを予定)

それなりに親しんでいただけていた EC studio という社名を
変更するのは勇気のいることでしたが、チャットワークというサービスには
それだけの可能性があると感じ、不退転の覚悟で決断しました。

今回は、チャットワーク開発の裏側というところで、この2年を振り返りながら
チャットワークを開発するまでの過程や、開発したなかで得たノウハウや
開発手法などをまとめて記事にしたいと思います。

開発のきっかけ

もともと EC studio では、7年ほど前から社内のコミュニケーションに
Skypeのテキストチャットをメインで使っていました。

Skypeのグループチャット機能は非常に使い勝手がよく、
部署ごとやプロジェクトごとに多数のグループチャットを作って
メーリングリストがわりに運用してきました。

ただ、長年使っているとSkypeチャットには下記のような問題がありました。

・双方がオンラインでないとメッセージが届かない(時間差で届くことも・・)
・チャットログの横断検索ができない
・PCとノートを使い分けるとチャットログが分散する
・スマートフォン版のテキストチャットの使い勝手が非常に悪い

これらの不満をかかえながらも、様々なサービスを試しましたが
代替できるようなサービスはありませんでした。

特に、GoogleからリリースされたGoogle Waveには非常に期待していたのですが、
時系列でメッセージが上から下へ流れていくという考え方がなく、
どこが新しい発言かわかりにくい・雑談が流れずずっと残ってしまう、など
チャットとしての利用は厳しいと判断しました。。。

もう待っていても自分たちの欲しいサービスは出てこないだろうと思い、
それならば自分たちで作ってしまおうと、開発を決心しました。

チャットワークの開発コンセプト

チャットワークの開発にあたって、技術的な開発コンセプトは大きく2つありました。

1. デスクトップアプリと遜色ない操作感を実現する。

Skypeチャットやメッセンジャーの優れている点の一つが、その軽快な操作性です。

リアルタイムに受信されるメッセージを、多数のチャットルームを
切り替えながら処理していくには、いちいち画面を読み込みなおしていては苦痛です。

GMailの様に、画面の読み込みがないフルAjaxでの開発を選択しました。

2. マルチデバイス対応。PCでもスマートフォンでも使いやすく。

チャットワークを開発する大きな動機の一つがモバイル対応です。

iPhone支給制度により全スタッフがスマートフォンを持つ環境はあったものの、
Skypeのスマートフォン版はPCで受信したものとログが別管理になっており、
PCで読んだログも未読のままになっていたり、過去のチャットログが遡れなかったりと
ビジネスで使うには実用的ではありませんでした。

データをクラウド化することで、PCでもスマートフォンでも同じデータを閲覧でき、
未読・既読の状態も完全に同期し、使い勝手の良いアプリの開発を目指しました。

デスクトップアプリと遜色ない操作感を実現するために

チャットワークはフルAjaxアプリケーションとして開発されているので、
大部分のコードがJavaScriptにより開発されています。

2012年4月現在のコード規模はフレームワーク、ライブラリ、HTML/CSSを
のぞくと大体JavaScriptで約4万行ほど、サーバーサイド(PHP)のコードは
約2万行ほどになります。

さすがに単体アプリケーションとしてこの規模のJavaScriptコードを
書いたのは初めてであり、PHPを中心とした従来のWebアプリケーションの
開発とは全く異なるノウハウが必要でした。

大規模JavaScriptの開発ノウハウについてはあまりWebにも
記事化されたものは少なく、まだベストプラクティスも
固まっていない状態かと思います。

あくまでもEC studioで採用したやり方ですが、うまくいった手法をご紹介します。

オブジェクト指向で書く

チャットワークはほとんどの処理をJavaScriptで行う必要があり、
コード規模が大きくなることが予想されたので、
はじめからオブジェクト指向で開発を行いました。

ただ、JavaScriptは文法的に非常に自由な言語なので、
オブジェクト指向といっても様々な書き方ができてしまいます。

ここはかなり悩みましたが、EC studioの技術部で慣れているPHPに
できるだけ近い書き方ができるよう、クラスベースに似せた
コーディング手法を採用することにしました。

例えば、下記のような書き方です

  1. function MyClass(){
  2.     var self = this; //自己参照にはself変数を用いる
  3.    
  4.     //プライベートプロパティ
  5.     var private_prop = ‘aaa’;
  6.     //パブリックプロパティ
  7.     self.public_prop = ‘bbb’;
  8.  
  9.     //プライベートメソッド
  10.     var privateMethod = function(){
  11.         //something
  12.     };
  13.  
  14.     //パブリックメソッド
  15.     self.publicMethod = function(){
  16.         alert(self.public_prop);
  17.     };
  18. }
  19.  
  20. //インスタンスの作成
  21. var MyObj = new MyClass();

この書き方に統一することで、PHPは得意だけどJavaScriptは経験が
少ないという開発メンバーでも、比較的すぐにJavaScriptのコーディングに
なじむことができました。(習得の容易さを優先しました)

JavaScript独特のクセのあるthisの挙動にも悩まされずすみます。

※この書き方については、過去に「PHPエンジニアのためのオブジェクト指向JavaScriptの書き方」という記事でまとめています。

ただ、この書き方では1つのクラスで複数のインスタンスが生成されるような場合に、
メソッドが共通化されずメモリ的にもったいないので、複数のインスタンスが
生成されるようなクラスの場合は、prototype継承を使った書き方を採用しています。

1ファイル、1クラスで書く

PHPでもそうしているのですが、JavaScriptでも クラス名.js というファイルに
そのクラス名のクラスを記述しています。

クラスごとにファイル

こうすることで、ソースコードの見通しが非常によくなります。

ただし、JavaScriptにはPHPのrequireのように、
別のソースコードを動的に読み込む仕組みがありません。
なので、この手法でファイルを作っていくとソースコードの読み込みは

  1.    <script type=”text/javascript” src=”Class1.js”></script>
  2.    <script type=”text/javascript” src=”Class2.js”></script>
  3.    <script type=”text/javascript” src=”Class3.js”></script>
  4.    <script type=”text/javascript” src=”Class4.js”></script>
  5.    <script type=”text/javascript” src=”Class5.js”></script>
  6.    <script type=”text/javascript” src=”Class6.js”></script>
  7.    …..以下続く

なんてことになってしまいます。
ブラウザはscriptタグのソースを順番に読み込んでいくので、
アプリケーションのロード時間が長くなってしまいます。

これでは問題なので、JavaScriptファイルを1つのファイルにまとめる
ビルドツールを自作し、本番リリース時にはそちらのファイルを
読み込むような仕組みにしました。

  1. <html>
  2.  <head>
  3.    <?php if ($local){ //開発時 1つずつ読み込む ?>
  4.    <script type=”text/javascript” src=”Class1.js”></script>
  5.    <script type=”text/javascript” src=”Class2.js”></script>
  6.    <script type=”text/javascript” src=”Class3.js”></script>
  7.    <script type=”text/javascript” src=”Class4.js”></script>
  8.    <script type=”text/javascript” src=”Class5.js”></script>
  9.    <script type=”text/javascript” src=”Class6.js”></script>
  10.    …..以下続く
  11.    <?php }else{ //本番時 all.jsにまとめる ?>
  12.    <script type=”text/javascript” src=”all.js”></script>
  13.    <?php } ?>

こんな感じですね。こうすることで、
開発時にはビルドの手間が不要になり効率よく開発でき、
本番時には読み込みの早いビルド版を使用できます。

ビルドツールの仕組みは単純で、読み込ませたい順番に
JavaScriptファイルの中身を連結していって、
一つのファイルにまとめてやるだけです。(PHPで作りました)

また、まとめるときの最後の処理として、
JavaScript圧縮ツールを使って圧縮処理をかけています。
これによりファイルサイズの削減効果があります。

※自社製ビルドツールの実行結果キャプチャ。圧縮するとサイズが大幅に減ります。
JSファイルを圧縮

チャットワークではJavaScript圧縮ツールとして
Google Closure CompilerYUI Compressor を併用しています。

Google Closure Compilerの方が圧縮率が良いのですが、
後述のモバイル開発ではエラーになってしまう場合があるので、
YUI Compressorも併用しています。

圧縮ツールを使うと、余白・コメントのカットや、
長い変数名などを短くしてくれる為、ファイルサイズを
気にせずコーディングができとても楽になります。

JavaScriptコードのテスト

コード規模が大きくなってくると、手動でのテストは限界になり、
自動テストが不可欠になってきます。

PHPであればPHPUnitなどのテストスイートライブラリで
簡単にテストを作ることができますが、ブラウザでの操作が前提の
イベント駆動型であるJavaScriptはテストが困難です。

ブラウザの操作を自動化するにはSeleniumというテストツールが有名で、
チャットワークでもSeleniumを採用しようとしたのですが、
どうしてもうまくいかず断念しました。。
(重かったり、動かなかったり、、、。複数のバージョンを
 かなりがんばって検証したのですが・・・)

というわけで、結局テストツールを自作することにしました。

※テストツールのキャプチャ。
「Run Test」ボタンをクリックすると自動で動作テストします。
テストツール

仕組みは単純で、テストケースを走らせるとjQueryで $(elem).click() のように
イベントをプログラムから順番に叩いて、各種DOMの状況を見てやるようなものです。

  1. var TR = new TestRunner();
  2.  
  3. //ボタンをクリック(ユーザー操作を実行)
  4. $('#cw_room_addchat').click();
  5. //結果を検証(結果をコンソールUIに表示)
  6. TR.isEqual($('.ui-widget-overlay').length,1,'ダイアログが開いたか');

↑簡単に書くとこんなイメージです。

実際は、テストケースを複数キューに入れて順番に走らせたり、
Ajaxの完了をwaitしたり、alert()やconfirm()で止まらないようにしたり、
XSS脆弱性がないか自動で検証したりなどもろもろ工夫しています。

コードの自動文法チェック

JavaScriptは様々なブラウザで挙動が変わるので、
あるブラウザでは問題なく動作するが別のブラウザでは
エラーになって動かなくなる、ということも実際よくあります。

jQueryなどのフレームワークを使えば問題は起きにくいのですが、
よくやってしまうコードとしては

  1. var obj = {
  2.     aaa:1,
  3.     bbb:2,
  4. };

という様に、オブジェクトの要素の最後のカンマを消し忘れると、
IEではエラーになってしまいます。(何度これに泣かされたか・・)

これはJavaScriptの仕様上は問題ないコードのため、
開発エディタなどではエラー検知されませんし、
開発でよく使うFirefoxやChromeでもエラーになりません。

このような問題に対応するため、前述したJavaScriptファイルをひとつのファイルに
まとめる本番用ビルドツールにコードの自動文法チェックの仕組みを実装しました。

※自動コードチェックでエラーを検出した場合のキャプチャ
セミコロン漏れと、最後の余分なカンマを検知。
JavaScript Lint

といってもJavaScriptの構文チェックを自前でやるわけではなく、
1つのファイルにまとめたJavaScriptファイルを、
JavaScript Lintというツールに読み込ませてコードチェックを行います。

このJavaScript Lintはコマンドラインのツールになっているので、
ビルドツールを実行する時にソースコードのパスを渡してやり
チェックをかけています。

これは非常に便利で、多数のバグになりやすいコードを指摘してくれるので
コードの品質を上げることができました。
(デフォルト設定はかなり細かいので、指摘条件をカスタマイズしています)

ビルドツールと組み合わせることで、このチェックに引っかかった場合は
リリースできないようにしています。

マルチデバイスでの並行開発にチャレンジ

チャットワークでは、Webアプリケーション版だけではなく、
iPhone・Android・iPadのアプリ版とブラウザ版を同時に開発しています。

EC studioではWebアプリケーションは得意としていましたが、
モバイルアプリなどは全くの専門外で、開発にあたっては大変苦労しました。

はじめは、まずはiPhone版をということで Objective-C を使って
ゼロから開発をはじめていきましたが、モバイル版を担当者が作っているうちに
Web版の仕様や機能がどんどんと変化していってしまうので、
モバイル版の開発がとても追いついていけないという問題にぶつかりました。
(Objective-CよりJavaScriptの方が開発速度が断然速い。。。)

Titanium Mobileを採用

そこでどうにかWeb版とモバイル版を同時開発していけないかと思い、
見つけたのが Titanium Mobile でした。

Titanium Mobile

ご存知の方も多いと思いますが、JavaScript で iOS、Android の
アプリケーションを開発できるクロスコンパイラツールです。

チャットワークはフルAjaxで作成されているので、
Titaniumとの相性は抜群です。

試してみたところ、ほとんどそのままのコードで動かすことができました。

MVCアーキテクチャの様に、ロジックやデータ処理を担当するModelクラスと、
表示部分を担当するViewクラスに分割し、Viewの部分だけを
Web版とモバイル版などデバイスで分けて書くようにしました。

※チャットワークのソースコードのフォルダ構造
ファイル構造

Web版のViewでjQueryを使ってHTMLを生成したりDOM操作していた部分を、
モバイル版のViewではTitaniumのUIViewクラスで実装します。

Titaniumの採用により、Web版とモバイル版でコードの大部分(約70%)を
共有できるようになり、大幅に開発効率を上げることができるようになりました。

Web版をバージョンアップすると自動的にモバイル版の機能も
アップデートされていくというのは感動ものです。

Titanium Mobile 開発の課題

ただ、Titaniumを使用することで開発効率は上がりましたが、
いろいろな課題にもぶつかりました。

いまではかなり改善されてきてはいますが、Titaniumは新しいツールだけに
非常に多くの不具合、メモリリークや挙動のクセがまだまだ残っており、
それを回避するためにトリッキーなバッドノウハウがたくさん必要です。

また、なんとか動かせたとしても、やはりネイティブの言語で書いた
アプリケーションに比べると、操作感が重かったり動作が不安定になったりします。

これらはアプリケーションレベルでチューニングができるものなのか、
そもそもTitanium本体の問題なのか切り分けが難しく、
いまでも開発に苦慮しています。

このあたりはTitaniumの進化に期待をしたいところですが、
限界も感じていて、ネイティブ版での開発を検討しはじめています。
(開発効率とパフォーマンスとのトレードオフですね・・)

これからのチャットワーク

チャットワークの開発をはじめてから、約2年。

社内用のツールをつくろうというところからはじまったこのプロジェクトが、
まさか社名にまでなり、米国法人までつくることになるとは思いませんでした。
(7月より、弊社代表が米国に移住して本格進出いたします)

この淘汰の激しいIT業界で、増資もせず上場もせず、
どこまで世界で戦っていけるかはわかりませんが、
創業してから12年かけてつちかったものをすべてぶつけて、
チャレンジしてみたいと思っています。

そのなかで得たノウハウは、またこのようにブログなどで
随時公開していければと思っています!

今後とも、チャットワークをどうぞよろしくお願いいたします。

アカウントをお持ちでないかたはぜひお試しください。無料です。

- 山本正喜(ChatWork ID facebook twitter)

※チャットワークの開発者を募集しています

正直、チャットワークの機能開発が追いついていません・・・。^^;

大規模JavaScript開発や、Webと連携するモバイルアプリの開発などに
ご興味がありましたら、ぜひエントリーを!


関連した記事:
投稿者
人気のエントリー
カテゴリー
最近のエントリー
アーカイブ
Copyright© ChatWork, All Rights Reserved. secured by ESET.