tech.kayac.com

Lobiチームインフラ担当の長田です。

今年は弊社で運用しているLobiというサービスについて、 サーバーサイドエンジニアの視点から、月いちくらいのペースで紹介していきます。

今回は「Lobiとはなんぞや?」というところを書こうと思います。

サービスの概要

Lobiはゲームを中心としたコミュニティサービスです。

Lobi Chat & Game Community

2010年のサービス開始当初はナカマップという位置情報を絡めたチャットサービスでした。 2013年にスマホゲームに特化するとともにLobiという名前に改名し、様々な機能追加の末に今に至ります。

様々な機能とは・・・

  • グループチャット
  • スマホゲームのプレイ動画録画・投稿・閲覧(Rec SDK)
  • マルチプラットフォームなスコアランキング(Ranking SDK)
  • スマホアプリへのグループチャット機能提供(Chat SDK)
  • ゲームに特化したプロフィール
  • ゲームのレビュー投稿・閲覧
  • 募集機能(マルチプレイ、ギルド等)
  • 広告入稿・配信
  • etc.

裏側で使っているもの

  • インフラ
    • Amazon Web Service (AWS)
  • 言語
    • Perl
    • Go
    • Javascript
  • ミドルウェア
    • nginx (openresty)
    • HAProxy
    • MHA
  • データストア
    • MySQL
    • AWS ElastiCache (Redis)
    • AWS Redshift
    • memcached
    • mongodb
  • その他ツール
    • chef
    • consul
    • packer
    • fluentd
    • jenkins
    • stretcher

簡易年表

技術的なトピック

  • stretcherを用いたデプロイ
  • チャットのストリーミングAPI
  • MySQLのシャーディング(水平分割)
  • MySQLのフェイルオーバー
  • iOSとAndroidのPush通知
  • プレイ動画の録画・変換・配信
  • web.lobi.co(w/AngularJS)のSEO
  • fluentdとNorikraを用いたログ集約・解析
  • AWS CloudSearchを用いたユーザー・グループの検索
  • AWS EC2上でのAutoscaling

すでに記事になっているものもあります。

ここに挙がっていないトピックについて紹介することがあるかもしれませんし、 挙がっていても取り上げない場合もあるかもしれません。 その辺りはご容赦ください。


次回は「stretcherを用いたデプロイ」について紹介します。

こんにちは、フロントエンドエンジニアのコウです!
この記事はTech KAYAC Advent Calendar 201524日目です。

小テスト

問題:CSSで、灰色の円 div.circle をラッパー div.wrapper の中央に配置する方法は?
CSSを下のテキストエリアに書いてください。.circle の高さと幅は 100px です。

See the Pen center the block both vertically and horizontally by GSSxGSS (@gssxgss) on CodePen.

できましたか?
おめでとうございます〜

どの方法をつかいましたか?
それでは、様々なセンターリングの方法を見てみましょう!


(プレビューコード画面右下の"+"と"-"を何回か押してみてください)

CSSレベル1の大先輩ーーvertical-aligntext-align

vertical-align プロパティは、インラインまたはテーブルセル要素の、縦方向の整列方法を定義します。 -- MDN

text-align プロパティは、テキストのようなインラインコンテンツが、その親ブロックの中でどのように文字寄せされるのかを定義します。 -- MDN

vertical-alignとtext-alignはCSSレベル1のプロパティなので、IE8のような古いブラウザでも安心してセンタリングに使うことができます。

table での解決方法

.table {
    display: table;
    width: 100%;
    height: 100%;
}
.wrapper.table-cell {
    display: table-cell;
    text-align: center;
    vertical-align: middle;
}
.target.inline-block {
    display: inline-block;
}

inline-block での解決方法

inline-block 要素を縦方向にセンタリングするためには、親要素の高さが重要です。
親要素の高さが定義されていない場合は
- 親要素に高さ100%で inline-block の擬似要素(:before or :after)を作る
- 親要素のline-heightをheightと同じ値にする
のどちらかが必要です。

方法1 height: 100%の擬似要素を作る

.wrapper.block {
    text-align: center;
    &:before {
        content: "";
        display: inline-block;
        width: 0;
        height: 100%;
        vertical-align: middle;
    }
}
.target.inline-block {
    display: inline-block;
    vertical-align: middle;
}

方法2 親要素のline-heightheightと同じ値にする

.wrapper.block {
    text-align: center;
    line-height: 465px;
}
.target.inline-block {
    display: inline-block;
    vertical-align: middle;
}

まとめ

inline-blockでの解決方法を使うときは親要素の高さが重要です。
またこの方法はIE8でも使うことができますが、複数の子要素をセンタリングしたい場合に、
子要素の幅の合計が親要素の幅を超えると、親要素をはみ出して表示が崩れてしまうので注意が必要です(画面右下の"+"を何回か押してみてください)。

inline-block要素はinline要素の特徴を持っているため、.targetの周りにはスペースができてしまいます。こちらも注意してみてください。

使いやすいなposition: absolute

もしセンタリングしたい要素が1つだけの場合、position: absoluteはとても便利です。

margin: auto での解決方法

この方法でもいけますが、ある場合にバグが起きるのでお勧めはできません。
何故この方法でセンタリングできるかについては、この記事に詳しく書いてあります

.wrapper.relative {
    position: relative;
}
.target.absolute {
    position: absolute;
    top: 0;
    left: 0;
    right: 0;
    bottom: 0;
    margin: auto;
}

ネガティブ margin での解決方法

IE8でも使うことができます。
しかし、.target自身の高さと幅に依存するので、使うときは注意してください。

.wrapper.relative {
    position: relative;
}
.target.absolute {
    position: absolute;
    top: 50%;
    left: 50%;
    margin: -50px 0 0 -50px;
}

transform での解決方法

transformはCSSレベル3のプロパティですが、IE9以降のブラウザ全てが対応しています。
おすすめです。

.wrapper.relative {
    position: relative;
}
.target.absolute {
    position: absolute;
    top: 50%;
    left: 50%;
    transform: translate(-50%, -50%);
}

flexの凄さ

flex要素は、ブロック要素のようにふるまいつつ、そのコンテンツを flexbox モデルに従ってレイアウトします。 -- MDN

flexboxモデルはすごく便利です。たったの3行で子要素をセンタリングすることができます。
勿論、センタリングだけではなくflexboxモデルはとても柔軟で色々なレイアウトに適用できるので、これから是非使ってください。

flexboxは3回仕様策定(box, flexbox, flex)されていて、ベンダープレフィックスもあるため、記述が複雑になってしまいます。
なので、compassやstylusやgrunt, gulp-moduleのautoprefixerを使うとよいと思います。
興味ある方はこの記事(flexboxの旧仕様、改定仕様、現行仕様の一覧)を読んで下さい。

IEは10以降、Androidは4以降で対応していますが複数行の場合、Andoroid4.3以下(4.0~4.3)で使えません。

一行センタリング例

複数行センタリング例

.wrapper.flex {
    display: flex;
    align-items: center;
    justify-content: center;

    // 下の二行は複数行対応です。
    align-content: center;
    flex-wrap: wrap;
}

サイトフレックスカエルで、Flexboxモデルを簡単に勉強できます。
是非試してみてください。

最後に

まだ日本語が上手くできないので、基礎的な話をしました。
来年のAdvent Calendarでは上手に発表できるように、日本語頑張ります!

それでは、また来年のAdvent Calendarでお会いしましょう。
皆さん、メリークリスマス!

以前はRubyを一番書いていたのですが、最近Swift書いています。 Optional型がすごく素敵な仕組みだと思いました。 基本的にnilの乱用を防ぐ仕組みなのですが、僕はRubyではnilに苦しめられた方なので、すごくOptionalがしっくりきました。

Rubyでのnil対策

Rubyでは型の概念はなく、変数にnilを渡すことができます。 しかも、nilだけでなくどんなクラスも宣言なしに変数に代入することができるため、開発時に変数にどんなクラスが入るかを限定することはできません。

Rubyではto_i、to_sなどのクラス変換メソッドを全てのクラス(nilも)の親クラスであるObjectクラスに実装することにより、nil対策をしています。 例えば変数の値がStringであることを想定している場合、変数利用側でto_sをかけてやることによってStringであることを確実にします。

2.2.1 :001 > nil.to_s
=> "" 
2.2.1 :002 > "aaa".to_s
=> "aaa" 
2.2.1 :003 > 1.to_s
=> "1" 
2.2.1 :004 > [1,2,3].to_s
=> "[1, 2, 3]"

このアプローチの問題点として、上記のようにto_sを挟むとフローが統一できていいんだけれど、その後ifがある場合に意図せずnilの場合と""(空文字列)の場合のフローが同じになったりします。

また、nilを防ぐためのこのアプローチの副作用として、サードパーティ製コードや、自作のコードに独自のto_sが実装されていると想定外の動きをしてしまうことがあるので、現実的には変数使う側が使われる側のクラスの知識を持たなくてはならなくなったり、理想と逆行してしまうことがあります。

問題点をまとめると

  1. nilの場合に何が起きるかわかりづらい。プログラマーが神経すり減らして自力で処理する必要がある。
  2. これを防ぐto_sなど使うと、すべてのクラスのto_sの実装を心配する必要がある

このrubyでの経験があった上でSwiftに入ったため、Optionalが非常にしっくりきました。

Swiftでのnil対策

SwiftではOptional型という型を導入することによって、その他の型にはnilを禁止しています。

では実際にこのOptional型を使うときにはどうするかというと、以下の方法でOptional型を剥いで(unwrapして)その中の元々の型をむき出しにしてからじゃないとつかえません。

Optional Binding

nilかどうかをチェックして、nilでない場合のみifの中の処理をする 上記のnilの場合に何が起きるかわかりづらい問題を解決しています。

var myClass: MyClass? = nil
if let nonNilMyClass = myClass {//myClass == nilの場合は入らない
  nonNilMyClass.myMethod()
}

ただ、これだけだとnilが入る可能性のある変数は常にチェックしなければならず、面倒になります。 この面倒を解決する方法として、以下の書き方もできます。

Optional Chaining

nilの場合はなにもしない書き方

var myClass: MyClass? = nil
myClass?.myMethod()

Rubyの場合と比べていいところは、nilの場合、nilでない場合のフローを明示的に表現できることによって、開発者の脳味噌のコストを減らせることにあります。 また、そもそもGenericsなどの仕組みを使わないかぎり、変数に想定外のクラスが入ってくることもないため、to_sの場合のようにいろいろなクラスのことを想定する必要もありません。

こういった理由によって、SwiftのOptionalが素敵だと思っています。

今回は「nilを防ぐ仕組み」という面にだけ注目しましたが、そもそも言語の思想の違いがあるのでどちらがいいとは言えません。 Rubyの理想形を求める姿勢は最高にクールです。 そもそもレベルの高いプログラマーが操れば、テストなどを併用することによって上記の問題もさらっと解決できると思います。 ですがその理想ゆえに、僕のようなレベルがあまり高くないプログラマーにとっては(または全員のレベルが高いことが保証されないプロジェクトにとっては)運用のコストが高くなることもまた事実だと思います。