ボクココ

サービス開発を成功させるまでの歩み

SaaS における企業毎のデータ管理について

ども、@kimihom です。

SaaS において悩ましいのが、企業毎のデータをどうやって管理していくかという話がある。企業毎にデータは完全に独立しているので、URL やデータそのものも独立している方が望ましいとされる。では SaaS においてデータベースの設計をどのようにやっていくといいのかについて、1つの方法を掲示したいと思う。

データを共通で扱う

私がオススメしたい方法はデータを共通で扱うやり方だ。これにより、Rails から個別のテーブル名にアクセスするといった複雑なテーブル接続からの悩みから解放される。そしてコードとしては至ってシンプルに実現できる点が利点である。

f:id:cevid_cpp:20171210183447p:plain

それ以外のデータも全て、Contracts に紐付けた 1 対多 の関係にすることが大前提だ。そうすれば、案外データを個別に取得することは Rails で簡単に実現できる。例えば、1つの Contract に対して複数の Invoice を取得するには以下のようなコードで実現できる。

class InvoicesController < ApplicationController
  before_action :authenticate_user!

  def index
    @contract = current_user.contract
    @invoices = @contract.invoices
  end

end

大事なのは、@contract.invoices といったようにして Contract に紐づいた Invoices しか取って来ないようにすること。この制約を入れるだけで同じテーブルだけど契約毎に限定されたレコードを取ってくることができる。とてもシンプルでメンテナンスしやすいコードである。データ取得する全てのコードにおいて、この制約を取り入れる必要がある。以下の例を見ていただきたい。

class InvoicesController < ApplicationController
  before_action :authenticate_user!

  def show
    # NG! 全く関係ないログインユーザーが、他の契約の Invoice を取って来れてしまう
    @invoice = Invoice.find(params[:id])
    # OK. 他契約の invoice id を指定したとしても Not Found となる
    @contract = current_user.contract
    @invoice =@contract.invoices.find(params[:id])
  end

end

慣れてくれば Invoice とそのまま呼び出すことに違和感を感じるようになる。そうすれば、間違っても NG なコードは書かなくなる。

他のデータ管理も共通の方法で管理する

例えば検索には Elasticsearch を使っている場合にも、同様の対応で実現が可能だ。Elasticsearch の場合、constat_score を使って contract_id を絞り込むことができる。

query = {
  :bool => {
    :must => [
     {
        :constant_score => {
          :filter => {
            :term => {
              :contract_id => 1
            }
          }
        }
     },
     {
        :query_string => {
          :query => "aaa"
        }
      }
    ]
  }
}

Contact.__elasticsearch__.search(query)

そうすれば Elasticsearch 側にも複数インデックスを作るみたいな大変なことをする必要がなくなり、コードがたいへんシンプルになる。

考察

別テーブルや別データベース、別サーバーといった形で契約毎に分けるのと、上記のような共有テーブルの方法のメリットデメリットについて考えてみたい。

1つのテーブルで共有する場合に真っ先に思いつくデメリットは、1つの企業が例えば超大量データを保有した時に、他の企業にもパフォーマンスで影響が出てしまうという点だ。そのため、例えば基本的に契約したらデータは無制限に保存できるみたいなサービスだと、この心配事が常につきまとうだろう。例え大きめの契約企業がいたとしても、データ保存容量を平等にすることで、心の平穏を保たなければならない。 でも、この件に関してはあまり心配する必要がないと思う。なぜならそもそも何億データも保存して共通データをやりとりしている BtoC のサービスが既に存在するからだ。SaaS でも今後データが増えてくればテーブルの再設計やテーブル分割など必要になってくるかもしれないけど、そこまで悩むレベルになってきたらサービスは成功したということなのだ。データベースをより良いものにアップグレードするなり専門のデータベーススペシャリストを雇うなりできるだろう。

共有テーブルの他のデメリットとして意図しないデータの共有が発生してしまうリスクもある。1人で開発している分には先ほどの NG なコードは書かないだろうけど、誰かがコードを書いている時に 一般的なモデル#find をやらかすケースは当然起こり得るだろう。そもそもそんなコードを書かないような仕組みや意識付けが必要となってくる。

そして最後に、上記のテーブル設計は 1ユーザーに1つの契約しか所属することができない。それを許容するのなら良いに越したことはないけど、例えばログインした時に複数の契約にスイッチできるようなことを考え出すと、このテーブル設計は破綻する。Contract-User の設計を多対多にして URL などで契約を識別できるようにする必要があるだろう。

実際運営している私からの意見として、デメリットというか意識しなければならないのはその点くらいで、他で問題になったことは今まで一度もない。今後、何かしらで共有テーブルで問題が出てくるかもしれないけど、別テーブルや別データベースで設計した時よりは深刻な問題にはならないだろう。"早すぎる最適化は諸悪の根幹" を忘れずにやっていきたいところである。

終わりに

今回は SaaS における企業毎のデータ管理について 1つの方法を掲示した。この件に関して難しく考えるよりも、まずは顧客が欲しいと思ってくれる機能を開発することに集中して欲しいと思う。そしてデータが多くなってきて管理に悩むくらいになったら、次のステップとして最適化について悩んでいけば良いのだ。

てな訳で難しそうと思わずにまずは作ってみてみよう!

最近の Twilio Client はココがすごい

ども、@kimihom です。 本記事は Twilio Advent Calendar 10日目の記事です。

f:id:cevid_cpp:20171206203748p:plain

今回は Twilio プロダクトの中でも Twilio Client に焦点を当てる。一応説明しておくと、Twilio Client はブラウザやスマホアプリ上で一般的な電話の受発信ができる技術のことだ。

私は常に Twilio Client の最新情報を追い続けてる立場なので、この機会に最近の Twilio Client の目玉機能について一気にご紹介する。

通話中の警告表示が可能に

Twilio Client で最も課題となるのが、通話品質の安定だ。一口に "通話が安定しない"と言っても、原因は多種多様で特定が困難な場合が多い。当然 Twilio 側もこの課題については把握しているようで、最近の Twilio Clinet は原因を見つけやすくする仕組みを多く提供してくれている。

その中で最も手軽な方法の一つが通話中の警告の表示だ。これは、Twilio Client で通話した時に渡される Connectionオブジェクトの warning イベントを補足することで取得できる。

Twilio.Device.connect(function (connection) {

    connection.on('warning', function(name) {
      switch(name) {
        case 'high-jitter':
        case 'high-rtt':
        case 'low-mos':
        case 'high-packet-loss':
          console.warn("インターネット接続が不安定です。");
          break;
        case 'constant-audio-input-level':
          console.warn("マイクが検出できません。");
          break;
        case 'constant-audio-output-level':
          console.warn("スピーカーが検出できません。");
          break;
        case 'ice-connectivity-lost':
          console.warn("通信が切断されました。");
          break;
      }
    });

});

これで通話中に例えば "インターネット接続が不安定です" と表示されれば、ユーザーは通話が途切れたとしてもインターネット接続が弱いことが原因だとすぐに理解することができる。これがわからないと何が原因だかわからない(PC? ヘッドセット? ネットワーク?)ので、問題の特定に時間がかかることになる。

このネットワーク周りの警告は、以前はそれなりに通話できる環境でも簡単に警告が発せられてしまったのだけど、最新の Twilio Client はだいぶうまくチューニングされているので、積極的に活用していくべきだと思う。

ice-connectivity-lost はドキュメントには載っていないけど、着信に対して複数 Client が同時に出た場合に稀に発生する警告で、この警告を取得してしまうと通話や今後の着信が一切受けられなくなる。本件はおそらく現時点(Twilio Client 1.4.25)での Twilio Client の1つのバグに近い動作なので、強制的にページを更新させることで対応している。

その他の通話品質の対策として Voice Insights ってのがある。これは正直今までは使い物にならなかったけど、最近のアップデートで強化されているみたい。一応紹介だけしておく。

Voice Insights Connectivity ダッシュボードのご紹介 - Twilio ブログ

着信音や発信音のデバイス切り替え

本機能は前から Twilio Client を使っているユーザーなら誰もが欲しいと思っていた機能のはずだ。

普通にヘッドセットを繋いで Twilio Client を利用していると、着信音もヘッドセットから鳴ってしまうので着信に気付きにくいという問題が発生する。この問題のために、今までは PC(OS) 側のサウンド設定でデバイスを切り替えたりするしか方法がなかった。

最新の Twilio Client では、着信音は PC 出力、通話音はヘッドセットといった切り替えが可能になっている。

Twilio.Device.audio.availableOutputDevices.forEach(function(device, id) {
  console.info('Available device:', id, '(labeled', device.label, ')');
});

まず上記で切り替え可能な発信音デバイスを取得することができる。例えば"内蔵" や "Sennheiser ~" といった Label と、ランダムな文字列の id だ。この id を Twilio.Device.audio.speakerDevices.set('id'); って感じにすると通話音デバイスの設定、Twilio.Device.audio.ringtoneDevices.set('id') ってすると着信音デバイスの設定が可能になる。

すごい簡単に実現できそうに見えるけど、実際に実装してみてわかったのは、設定途中にデバイスを抜き差しされた場合の対応や、ページをリロードされた場合の再セット方法など、色々と考えてやらないといけない部分がそれなりにある。 一番簡単なのはページに入るたびにデバイス選択のセレクトボックスが出てきて、それを選択すると設定が適用されるような使い方になる。

ちなみに本機能は現時点では Google Chrome のみのサポートとなっている。他のブラウザサポートは Twilio Client の Browser Compatibility を参照していただきたい。

着信音のカスタマイズ

Twilio Client で着信を受ける場合、着信音のデフォルトは「ちゃんちゃんちゃん♪」 といった音が流れる。これを普通の Brrrr 音にしたいっていう要望は少なからず出てくるだろう。

てことで最近の Twilio Client は着信音を独自に指定できるようになった。その方法は簡単で、 setup 時にそれぞれの音の URL を指定すれば OK。この mp3 は CDN に置くなど、できる限り早くダウンロードできる環境にしておいたほうが良さそう。というのも最初の着信の時に音声の読み込みが数秒かかっても取得できない場合は、着信音が鳴らない問題を引き起こす可能性があるためだ。ここで今まで何回かトラブったことがある。

Twilio.Device.setup(token, {
  sounds: {
    incoming: 'http://mysite.com/incoming.mp3',
    outgoing: 'http://mysite.com/outgoing.mp3',
    dtmf8: 'http://mysite.com/funny_noise.mp3'
  }
}

Safari 対応

つい先日、iOS の WebRTC 対応が WebRTC 業界を騒がせたことをご存知だろうか?この Apple の遅すぎる WebRTC 対応によって、ついに iPhone でも WebRTC が使えるようになった。しかし、その仕様がかなり独自めいたこともあり、最近の Twilio Client で Safari のための特別対応のリリースが施されている。

ただし、iPhone で Twilio Client(WebRTC) が使えるようになったからといって、完全に iPhone の電話アプリを Twilio Client にリプレースするにはまだ時間がかかる。とりわけ通話の着信を Twilio Client で受ける場合に、iPhone/Android はスリープが走ってしまうと意図も簡単に着信を受けることができなくなってしまうからだ。今後、Service Worker などの HTML5 の発展により解決されていくと思うが、Apple としては Web化ではなくネイティブアプリ化を断固として保持していく様子が見て取れるので時間がかかりそうだ。

In The Future...

最近の Twilio の動向を見ていると、エンタープライズ向けコールセンターで Twilio が使われるようになることを目指している傾向が強い。

  • TaskRouter によるオペレータースキルに応じた自動分配
  • Twilio Addons による WFM(ワークフォースマネジメント) や通話の統計分析
  • セキュリティの向上 (Twilio Interconnect)
  • Conference でのウィスパリング/モニタリング

個人的に特に注目しているのは Agent Conference だ。KWC さんがこの速報を記事として書いてくれたのでご紹介しておく。

Agent Conference 正式リリースのご案内 - Twilio ブログ

それなりにオペレーターを抱える規模になると、初心者オペレーターの通話をスーパーバイザーと呼ばれる管理人が通話に入り込み、適切なアドバイスや情報をリアルタイムで行いたいというケースが発生する。まさに Twilio は3者間通話を実現するための <Conference> 動詞があるのだが、これではスーパーバイザーの声も相手に丸聞こえってことで、課題があった。

AgentConference の "coach" オプションってのを使うと、カンファレンス内で特定のオペレーターのみささやく(ウィスパリング)ことができ、通話全体を聞く(モニタリング)ことができるようになる。

早速これを試してみたのだけど、 Twilio Client を利用することを想定した場合、まだ実用段階ではないと感じている。特に、1つの着信があった際に、最初からその着信の Dial 先を Client ではなく Conference にする必要があり(通話料の高騰)、しかも複数のオペレーターに対してその着信を鳴らした時に同時に接続してしまうと意図しない着信の出方(同時着信による意図しない3者間通話)が生まれてしまったりする。

色々調査したが、この対策は現状無いように見える。先ほどの Twilio Blog に今後の Conference の拡張について、モニタリング、指導、割り込み通話をTwiMLを使用することなくシームレスに切り替える, ブラウザーからカンファレンスを準備するためのSDK などが提供予定とある。なるほど、この問題は Twilio も同じように感じているようで、今後改善されていくようだ。

おまけ

実は Twilio Client 1.4.9 の デバイス選択の機能をリリース以降、通話を開始したのに着信音がなり続けるバグや、同時に複数県着信が来た時に着信音が二重でなったり他の Client が1つめの着信に出た後の残りの着信の着信音が聞こえなくなる といった問題を抱えていた。

そのため、上記の最新機能を利用することができていなかったのだけど、Twilio Client 1.4.22 でようやく解決され、現在は安定して利用することができる。この問題の再現やバグ修正の確認のために今まで何回 Twilio Client で着信を受けたのかわからなくなるほどだった。最新の Twilio Client を使い続けることはリスクであることも知っておくといいかもしれない。反対に積極的に Twilio Client のバグを踏んで Twilio へ報告しまくる気概のある方、ぜひ一緒に最新の Twilio Client を追い続けていきましょう。

ちなみに今回のような変更リリースは Change Log から見ることができる。Twilio Client をガチで使う場合には定期的にチェックして何が新しくなったのかを確認すると良さそうだ。

終わりに

Twilio の情報を共有するミートアップである Twilio Lounge が特別版として公開されている。LT 付きの年末豪華版なので、ぜひ参加して欲しい! 私からは "開発者から見た Twilio Signal 2017" として Twilio Client だけでない最新情報を共有したいと思う。

Twilio Lounge Vol.5 - TwilioForKWC(株式会社KDDIウェブコミュニケーションズ) | Doorkeeper


[宣伝] 本記事のように最新情報を追い続けている ブラウザ電話システム CallConnect があるので、こちらもよければチェックいただけると幸いだ。

www.callconnect.jp

日本発 Global SaaS を生み出すための条件

ども、@kimihom です。この記事は Stripe Advent Calendar 2017 9日目です。

f:id:cevid_cpp:20171208224210p:plain

自分の作ったサービスが世界中で使われるようになるという夢を実現したい。そんな思いを持った方は多くいるかと思う。私も、そんなエンジニアの一人だ。

じゃあそれに向けてどんなサービスなら勝負に出られるのか、そんなことを個人的な意見ではあるけども書いていこうと思う。ちなみに以下のことを実践してうまくいったとかそういうわけではなく、これからの開発で意識していこうというだけの話なので、そこは大目に見ていただきたい。

Global SaaS を生み出す土台

実は、誰もが SaaS として世界に飛び出すことのできる環境が整ってきたのはつい最近のことである。今まで最大のハードルとなっていたのが、決済方法の問題だ。従来の銀行振込やクレカ決済では国内のサポートのみに限定されていて、世界展開するにはその国ごとの決済手段を導入するしかなった。

でも時代は変わってきている。お分かりの通り Stripe の登場だ。Stripe の決済 API によって、私たちは世界中のユーザーのクレジットカードを使って決済を実現できるようになった。Stripe が日本にやってきたのはつい最近であることを考えると、ようやく私たちが日本発 Global SaaS として挑戦できる土台が整ったことになる。

今まででも、無料のアプリやサービスで世界中に使われているものはいくつかあるかもしれない。しかし、海外での売り上げが大半を占める国産 SaaS というのはまだほとんどない状況だ。ここにチャレンジしていこうとする人が今後増えてきてもおかしくはない。

ではどんなことを意識すべきか。私なりの意見を書いていく。

とにかくシンプルを目指そう

ちょっとでもわかりづらい点があれば、その時点でユーザーは問い合わせが必要になる。てなると、グローバルで展開するには各言語を扱える人材が必要になることだろう。それじゃあいつまでたっても世界に向けてどんどんやっていくなんてことは難しい。

世界中の誰もが使っても、問い合わせが必要のないサービスを目指そう。私たちが目指すべきは Facebook ではなく スーパーマリオブラザーズだ。ユーザーが勝手に学んで勝手に使いこなせるようになってくれる。それこそが Global SaaS の理想形だ。

f:id:cevid_cpp:20171208222355p:plain

世界ではあらゆる文化や風習が存在する。それによって、日本のサービスでは常識だったようなことも、世界レベルで見渡すと違和感のあるサービスができてしまうかもしれない。これはその他でうまくいっているサービスを参考にする必要があるかもしれない。

シンプルにしていけば、そこのページに出さなければならない文字列も当然減ってくる。そうすると、サービスごとの翻訳の手間なども必要なくなるし、ランディングページに複雑な機能一覧を出す必要もなくなる。私が常日頃から言っているように、サービスのコア機能にのみ集中し、そこだけで勝負して世界 No.1 を目指せばいいだけだ。

個人的に気に入っているサービスとして Noisli がある。これは完全にツール系だけど、この発想をベースに SaaS として何かできないか考える価値はあるかもしれない。実際、世界中で Noisli は課金されて使われているようである。

https://www.noisli.com/

勝負どころを見極める

これは世界向けじゃなくても当たり前の話なんだけど、何で勝負するかってところは重要だ。 でも、その勝負どころで競合の世界展開しているサービスにちょっとでも優ってて、ユーザーがそれが良いと評価してくれたのなら、私たちが作ったサービスを使ってくれる可能性は出てくる。

日本ならではの勝負どころをうまく見極めたものの1つとして Tokyo Otaku Mode がある。こちらは世界中の日本の"オタク"文化に興味のある人たちがこぞって集まる人気サイトだ。実際こちらのサービスも Stripe を活用されているそうである。今後、海外売り上げを占める割合は日本のオタク文化の世界展開とともにどんどんと増えていくことだろう。

でも別に日本ならではの風習を世界に持っていくって発想である必要もないと思っている。世界中で共通の課題を1つだけ解決する何かであればなんでも良いのだ。

さらに理想としては、1人1人が勝手に広めていってくれる仕組みがあれば最高だ。1人だけ使っていれば便利なツールレベルだと、どうしてもその人だけのサービスとなってしまうので他の人が新しく知るきっかけを生み出すことができない。SNS でシェアしたくなるような何か。これを1つだけでも持たせれば、後はユーザーがユーザーを呼び込んでくれる仕掛けができあがる。

おわりに

自分が作ったサービスが、世界中のユーザーに使われている。これは裏を返せば、"自分が世界の一部を変えた" と言い換えられる。

そのための土台は整ったので、後はやるかやらないか。それだけの話なのだろう。

大志のあるエンジニアが出てきて、思いっきり世界に羽ばたくサービスが出てきてほしい。そして私もその中の一人となれるよう、今後も頑張っていく次第だ。

Rails 5.1 アプリを Heroku にデプロイする

ども、@kimihom です。 この記事は Heroku Advent Calendar 8日目の記事です。まだ3枠空きがありますので、Heroku ユーザーの方はぜひご登録を!

f:id:cevid_cpp:20170929233715p:plain

Rails 5.1 から Yarn のサポートが入り、フロントエンドの JavaScript ライブラリの管理が容易になった。そこで Rails 5.1 で作った破壊的イノベーションを生むアプリを意気揚々と Heroku へデプロイしようとしたところ、色々詰まったので残しておく。

遭遇した問題と対応

Rails 5.1 の Yarn サポートにより、yarn install を実行しないといけなくなった。 しかし、 Heroku の Ruby ビルドパックに yarn install のコマンド実行が入っていないので、git push した時点で JavaScript パッケージをインストールしてくれない問題が発生した。結果、JavaSciript を読み込むことができず Heroku 側で JavaScript エラーが発生してしまった。

こういう時こそ Release Phase の出番かと思ってやってみたけど、うまくいかず。

色々と調べていると、Node.js のビルドパックを追加する方法があった。具体的には

heroku buildpacks:add --index 1 heroku/nodejs

とすることで、 heroku/ruby の前に nodejs のビルドパックを埋め込んでくれるようだ。ビルドパックを複数指定して、git push heroku master 後にその順番でビルドしてくれる。そうすれば、Node.js のビルドパックには yarn.lock を読み込んで node_modules を生成してくれるので、デプロイがうまくいく。実際に以下のコマンドを叩いてみると、

$ heroku buildpacks
=== my-awesome-app Buildpack URLs
1. heroku/nodejs
2. heroku/ruby

といった感じで複数のビルドパックが入っていることが確認できる。この状態で、git push heroku master をやってやると、Rails ルートにある yarn.lock を読み込んで勝手にライブラリをインストールし始めてくれる。

$ git push heroku master

Counting objects: 7, done.
Delta compression using up to 4 threads.
Compressing objects: 100% (7/7), done.
Writing objects: 100% (7/7), 676 bytes | 0 bytes/s, done.
Total 7 (delta 6), reused 0 (delta 0)
remote: Compressing source files... done.
remote: Building source:
remote:
remote: -----> Node.js app detected
remote:
remote: -----> Creating runtime environment
remote:
remote:        NPM_CONFIG_LOGLEVEL=error
remote:        NPM_CONFIG_PRODUCTION=true
remote:        NODE_VERBOSE=false
remote:        NODE_ENV=production
remote:        NODE_MODULES_CACHE=true
remote:
remote: -----> Installing binaries
remote:        engines.node (package.json):  unspecified
remote:        engines.npm (package.json):   unspecified (use default)
remote:        engines.yarn (package.json):  unspecified (use default)
remote:
remote:        Resolving node version 8.x...
remote:        Downloading and installing node 8.9.1...
remote:        Using default npm version: 5.5.1
remote:        Resolving yarn version 1.x...
remote:        Downloading and installing yarn (1.3.2)...
remote:        Installed yarn 1.3.2
remote:
remote: -----> Restoring cache
remote:        Loading 2 from cacheDirectories (default):
remote:        - node_modules
remote:        - bower_components (not cached - skipping)
remote:
remote: -----> Building dependencies
remote:        Installing node modules (yarn.lock)
remote:        yarn install v1.3.2
remote:        [1/4] Resolving packages...
remote:        success Already up-to-date.
remote:        Done in 0.12s.
remote:
remote: -----> Caching build
remote:        Clearing previous node cache
remote:        Saving 2 cacheDirectories (default):
remote:        - node_modules
remote:        - bower_components (nothing to cache)
remote:
remote: -----> Build succeeded!
remote: -----> Ruby app detected
remote: -----> Compiling Ruby/Rails
remote: -----> Using Ruby version: ruby-2.4.2
remote: -----> Installing dependencies using bundler 1.15.2
remote:        Running: bundle install --without development:test --path vendor/bundle --binstubs vendor/bundle/bin -j4 --deployment
remote:        Warning: the running version of Bundler (1.15.2) is older than the version that created the lockfile (1.16.0). We suggest you upgrade to the latest version of Bundler by running `gem install bundler`.
remote:        Fetching gem metadata from https://rubygems.org/...........
remote:        Fetching version metadata from https://rubygems.org/..
remote:        Fetching dependency metadata from https://rubygems.org/.
remote:        Using rake 12.2.1
remote:        Using concurrent-ruby 1.0.5

... 以下 Ruby のビルドパックの実行

その他の方法

どうやら Webpacker を入れておけば、勝手に Yarn のインストールが走る? そうだ。参照元がどこだか忘れたので、もしかしたら間違ってるかも。

ただ自分は AssetPipeline で普通に Rails のフロントエンドを扱いたかったのでそのために Webpacker の形式に最適化することはしたくなかったので、やっていない。

(余談) Webpacker を入れると、以下のコマンドを実行するわけだけども、

bundle exec rails webpacker:install

てすると

app/javascript:
  ├── packs:
  │   # only webpack entry files here
  │   └── application.js
  └── src:
  │   └── application.css
  └── images:
      └── logo.svg

っていうディレクトリ構成になる。なんかもうこの構成の時点で使いたくなくなるよね。なぜ javascript の中に csssvg が入るのか?そして layouts に <%= javascript_pack_tag 'application' %> という 記載しなければならないもクールじゃないので使用するのを止めた。今後のアップデートに期待、かな。

終わりに

現在、heroku.yml という機能が Developer Preview で公開されていて、今後は heroku.yml でこの問題が対応できるようになりそうだ。これも注目していきたい。

まだまだ Rails のフロントエンドの開拓は進んでる最中なので、色々と躓くところがあるかとは思う。でもYarn をちゃんと使って JavaScript ライブラリの管理ができれば、それはそれで良いに越したことはない。

Heroku は Ruby の最新版をリリースした数時間後に最新版 Ruby のサポートを発表したり、最新の Rails アプリケーションもどんどんサポートしてくれるので、新しい何かを試すのにいいプラットフォームだと思う。

Rails 5.1 以降のフロントエンド周りの発展にも期待していきたい。

アドベントカレンダーの価値について

ども、@kimihom です。最近は東京でホテル暮らしの日々を過ごしてます。

f:id:cevid_cpp:20171129202422p:plain

いよいよ12月も近づいてきて今年も終わろうとしている。12月といえば、とりわけ開発者の間では Qiita のアドベントカレンダーで記事を書くというのが定番となりつつある。このアドベントカレンダーについて今回は書いていこう。

アドベントカレンダーの魅力

アドベントカレンダーで個人的に何が気に入っているのかというと、一緒に情報を作り上げていくという感覚を得られるという点だ。アドベントカレンダーのようなイベントがないと、とりわけ自分でブログを持っていない方だったり、ほとんど記事を書くことのしない方にとっては記事を書くいいきっかけとなる。今年の "情報"が 集まる場所がアドベントカレンダーだ。そんな素敵な情報を同じ興味のある仲間同士で作り上げていく感覚が気に入っている。特定の技術で集まって、一緒に作り上げていく感覚ってのは他ではなかなか味わえない。特に同じコミュニティでのアドベントカレンダーだと、知り合いの記事を読むことができたりするのも、楽しみが増すポイントでもある。

私は日頃から使っている TwilioHeroku のアドベントカレンダーにそれぞれ登録をし、記事を書いてくれる方を Twitter などで募っている。ちなみに今もそれぞれ空きがあるので、ぜひ登録して欲しい(!)

「初歩的な内容だけど大丈夫かな?」とか「技術あんま関係ないけど大丈夫かな?」などの心配はしなくて OK。アドベントカレンダーは Qiita 以外でも記事を書いてシェアすることができるので、テーマに即した内容なら大丈夫だ。そこまで難しすぎる内容をアドベントカレンダーに書いてほとんどが理解されない記事を書いても仕方がないので、私は割と色々な方が理解してもらえるような記事を書こうと思う。もちろん、その記事は本ブログで公開する予定だ。

記事を書く習慣を。

ほとんど記事を書くことをしない方は、強制的に始めてみよう。そしたら来年はもっと記事を書けるようになるって一つの目標が生まれるかもしれない。

記事を書くことってのは、一見 情報を"与える"だけに見えるかもしれないけど、実際は情報が"集まる"場所を作ることができる魅力がある。私自身、今まで色々な記事を書いてきて読者の方から色々な情報を得ることができてきた。これらの情報ってのは一度発信をしないと、相手に伝わることもなかったし、得られることもなかった。何も書かなければ何も始まらない。でも何かを書けば何かが始まる。それを実感してから、さらにブログで記事を書く習慣を身に付けることができたように思う。

そして記事を書くことは、深く考える習慣を身に付けることができる。最初ぼんやりとして考えたテーマでも、次第に記事を書き始めると勝手に記事のテーマについて深く考えるようになる。この習慣ってのは仕事でも確実に役に立つスキルである。

てことでアドベントカレンダーをその最初の一歩にしてくれたらいいと思う。そのためにも、Twilio/Heroku のアドベントカレンダーで登録してくれた記事に関しては1日1日ちゃんと読むようにして、何かフィードバックがあれば進んで返したいと思う。情報を発信したことで得られるメリットを十分に得られるように協力していきたい。

終わりに

今回はアドベントカレンダーの話だったけど、普段記事を書き続けていく上で大切なことの記事は以前に書いたのでシェアしておく。

www.bokukoko.info

いよいよ明後日から始まるアドベントカレンダーに向けて思いを書いてみた。今からどんな記事が出てくるか、楽しみにしている。

少数精鋭チームでサービス開発を続けるためのヒント

ども、@kimihom です。

f:id:cevid_cpp:20171123200450j:plain

最近は色々な企業がサービス開発は少人数でやる方がいいことに気付き始めて実践しているように見受けられる。もちろん、最初の 0->1 フェーズでは設計して開発するだけなので誰でも少人数で開発していけるだろう。しかし問題はその後でサービスを公開してユーザーが増えてきたときに人が足りないみたいな状況になってしまってどんどん人を増やしてしまうケースが見受けられる。本記事では少数精鋭チームで開発を続けられるようにするためのヒントを記していく。

問い合わせを減らそう

サービス公開してユーザーがどんどん増えてきたときに、問い合わせがそれに比例して増えていくようでは、当然のことだけど運営側も人が必要になってくる。問い合わせ、つまりユーザーが疑問に思ってしまう点をいかに減らしていくかが少数精鋭を続けるために重要な点となる。

そのためには、ユーザーを悩ませないサービスを目指していけば良い。使えば誰でもわかるサービスだ。少数精鋭だからこそ、サービスに最も必要な機能だけに重点を絞り、そのほかのあったらいいな程度の機能はあえて実装/提供しない。こうすれば、ユーザーはどうすればいいのか迷うことがなくなり、最終的に問い合わせそのものを減らすことができる。

私がこの話で例をよく出すのが appear.in というサービスだ。このサービスは話したい相手と URL を共有するだけでビデオ通話ができてしまうサービスである。ビデオ通話だけできるサービスなので、ユーザーは一切迷うことがないし、"誰かとビデオ通話したい" = appear.in というユーザーの意識の紐付けが簡単にできるため、再び気軽に使える強力なフックがある。appear.in で使い方がわからない っていう問い合わせはまず来ないだろう。そうして appear.in はサービスにおいて最も大切な通話品質を高めることに注力することができるのだ。

誰も悩まないレベルのサービスを提供できれば、問い合わせは劇的に下がり、少数精鋭を保ち続けることができるのである。 上記のために間違ってもわざとメールや電話の問い合わせ窓口をわかりづらくさせるみたいなバッドノウハウを実践しないようにして欲しい。

単純な手作業を全て自動化しよう

普段の仕事の中で、単純な手作業で入力している項目がないか?こうした時間は無駄以外の何物でもない。単に仕事をしている気になっているだけだ。こういう作業こそコンピュータの得意な分野なのに、それを活用しないってのはあまりにも勿体無い。

ここで必要になってくるのはやはり一定のプログラミングの知識だと思う。何かがあったら自動でプログラムが動いて手作業を自動化させる。毎日5分くらいの作業だからとか言って単純作業を許容してみるとしよう。それは 1年経てば営業日を300日だとすると1500分(25時間)を無駄にしている。そういう作業がどんどん増えていってしまうと、やがて人が必要になってしまうのである。

だからこそ、エンジニアでなくても業務の効率化を身につけている人はエクセルのマクロを勉強したりするし、サービスの自動化の仕組みを学んだりするようになる。それは少数精鋭でやる上ではとても大事な意識づけだと思う。

余計な仕事を増やさない工夫をしよう

サービス開発に関わること以外は、できる限り少なくすることが大切だ。仕事においてどうしても時間をかけてやらないことがあった場合には、それらを外の人に手伝って(外注して)やってもらう方法を検討しよう。そこでサービスの良し悪しは変わるものではないので、時間をお金で解決するってのは大事な考え方だと思う。これを勘違いしてサービス開発の根幹である開発やデザインを外注するってのは当然ながら NG だ。

また、余計な仕事を増やさないようにするために、サービスのターゲットとなる顧客だけを相手にしていく努力も必要だ。ターゲットでない人がサービスを使ってしまうと、その時点で "~はできないですか?" といった問い合わせが増えるし、その検討や対応に時間を取られることになる。少数精鋭チームであれば、百万ユーザーなんて必要なく、数百 ~ 数千の顧客を相手にすれば十分にうまくやっていくことができる。そんな理想な顧客とだけ相手にしてサービスをどんどん良くしていくってのこそ、少数精鋭チームでのサービス運営の醍醐味である。

終わりに

今回は少数精鋭チームを続けるために必要な考え方について記した。

来月、"自己資本主体で少数精鋭チームでサービスを成長させるには" ってテーマでイベントをやる予定だ。本記事で書かれたこと以上に有益な情報が共有されるはずなので、残り席少ないけども興味があれば参加いただけると幸いだ。

selfree.connpass.com

少数精鋭チームで最高のサービスがどんどん出ていくと、それぞれの顧客にとって"最適な"サービスを選べるようになり、みんなが幸せになれるはずだ。

全ての企業がテックカンパニー化する世界

ども、@kimihom です。ちょっと気分が優れなくて一時的にブログ止まっちゃったけど、またコツコツ再開しようと思う。

f:id:cevid_cpp:20171115203603p:plain

さて近頃は、日経電子版がめちゃくちゃ速いみたいな感じで話題になっている。

リニューアルした日経電子版が高速すぎてヤバイ件|こんぴゅ|note

本記事を読むと、確かに従来のウェブ開発に乗っ取った設計ではなく、Web や HTTP プロトコルの最新の機能を駆使してとんでもない高速化を実現したことが理解できる。日経のような大きな組織でこのチャレンジは本当にすごいことだと思う。

その技術力もさることながら、それを実現したのが新聞社だということが新しい時代を感じさせてくれる。本来であればニュースの記事を取材してそれを公表するのが新聞社のはずだ。それなのに、日本の Web 企業ですらなかなかチャレンジしづらかった最新技術への適用を日経がやってのけたってことが私にとってもっとも衝撃的だった。

そしてこの点から一つの真理が言えるだろう。これからはどの業界でもテックカンパニー化していくという点だ。"自分たちは専門外だから"といって技術を丸投げするような企業は改めてこの点について考えるべきだと思う。

テクノロジーが今後を左右するワケ

どんなビジネスにおいても情報は宝の山だ。顧客が何を望み、現状の何に満足しているのか。本気で情報を解析している組織にはそれをカンではなく確かな情報として理解することができる。どの時間に何をすれば顧客は購買してくれるのか。そんな傾向がわかれば、どこへ重点的にリソースを割くかといった戦略を立てることが可能になる。

これは例えるならマグロ漁師が沖へ出ていって、単なる勘で探しに行くのではなく、海の中をセンサーを使って覗きながら確実にいるとわかった状態で網を投げるといったのに近い。どちらが確実にたくさんの成果が得られるのか、想像に容易い。情報が全て筒抜け的な話でいうと怖くなるというか嫌だなと思う方もいるかもしれないが、そうしたちゃんと根拠に基づいた行動ができるようにならないと、今後どんどん相手が利益をかっさらって行くだけの状況となってしまう。

こんな話は今までそれなりの規模でエンジニアを抱えている企業だったら当たり前の話だったかもしれないけど、これが今後は他のどの業界にでも必須になってくる。そう考えると日本にエンジニアが足りないって言われるのは当たり前の話なんだと思う。

ちなみに今回の日経電子版は相当の知識や経験がないと踏み込めないところまでやってのけていることを考えると、優秀なエンジニアを自社で抱えてやっているように思う。実際何度かテック系のイベントを日経社が会場提供していたし、すっかりテックカンパニーになったように見える。

ページの表示速度が2倍速くなったってなら、他のニュースサイトに比べたら3倍以上は早いだろう。数秒ならあんま気にならないという話があるかもしれないけど、何百万ユーザーレベルの視点で見れば確実にユーザーにとってプラスに動く改善だ。

こんな変化が実はあらゆる業界で発生している。飲食チェーン、金融、商社、運送、農業まで全てがテクノロジーを駆使して業務の改善や分析をベースとした経営判断を行うようになってきている。そしてそれができるトップ企業だけが、海の中のセンサーを活用してマグロ漁をするかのように大量の成果を得られるような時代が既に来ている。

私たちはどうすべきか?

自分はエンジニアなので引き続き技術を学んでいくってところだけども、そうじゃない人でもプログラミングやコンピュータの基礎知識は持った方がいいと思う。そうじゃないとそもそも何ができるのかもわからない状態になってしまう。これではどんどん先を越されていってしまう。

テクノロジーを駆使した企業がどんどん成功して、そうじゃない企業はどんどん取り残されると、業界トップ1~2位の企業がほとんどを独占するような感じになると思う。上下の差がますます広がっていってしまうけども、競争社会ってのはそんなもんだろう。個人的にはあんまガツガツしたくないけど、それでもしっかりとテクノロジーを駆使するところはブレずにやっていきたいと思う。

終わりに

一部ではエンジニアを崇拝しすぎるのもどうかっていう意見もあると思うけど、エンジニアを軽視しているところは間違いなく今後取り残されるだろう。程よい関係を構築しながらエンジニアが長く、そして成長できる基盤を整えていくことがこれからの企業に求められることだ。

今回の日経電子版のニュースはそれほどまでにすごいと個人的には思った。