ISUCON夏期講習に参加した

ISUCON

去年のISUCON3の予選にも出たんだけど、FAILしまくってダメだった( 第三回ISUCONの予選に出たけどダメだった - 明日から本気だす )ので、今年こそ予選突破するため(?)に夏期講習に参加してみました。

会場は、LINE社のセミナールーム的な部屋でした。

入り口がめっちゃ緑色だったり窓口?がすごく綺麗でした。

お話

LINE社の採用の話とか、ISUCONについてなどのお話がありました。

次に過去問にチャレンジがあったのですが、その途中でもヒントとかテクニックの解説を聞けました。

過去問にチャレンジ

ISUCON3の予選問題に似ている感じの過去問を、その場で解くこともしました。

自分ができたこと(&スコアに反映できたっぽいこと)は、

  • apacheをnginxに置き換える
  • unicornのワーカ数を変える
  • mysqlにindexを貼る
  • Webアプリ(sinatra)の実装を修正する
    • 使っていないところでSELECTを呼んでいたのを消す
    • アイテム数を表示するためにCOUNTを呼んでいたのをMAX(id)に置き換える

くらいでした。

途中途中で解説があって、めちゃ面白そうな話っぽかったのですが自分の作業が中途半端だったせいで話半分にしか聞けませんでした、残念。

初期状態では1700点くらいのスコアが最終的に2500点位になったのですが、中の人は9000点超(!?)したなどを聞いてびっくりしてました。

懇親会

渋谷ヒカリエの裏らへんにあった、オサレなとこで懇親会までありました。 久しぶりにピザとか食べまくりました。

他にも、LINE社の中の方のお話を色々聞けて楽しかったです。

Effective Java

Effective Javaを読み始めたのでメモなど

項目1 コンストラクタの代わりにstaticファクトリーメソッドを検討する

普通にクラスのインスタンスを生成するならばコンストラクタを使用するけれど、コンストラクタよりもstaticファクトリーメソッドを使ったほうが良いケースがある。

staticファクトリーメソッドの利点

  • staticファクトリーメソッドは、コンストラクタと違って名前を持っているため、仮引数の名前とかコメントだけに頼らずにわかりやすい。
public class Hoge {
  // コンストラクタ
  // "Hoge"クラスなのでコンストラクタの名前はHogeになってしまう
  public Hoge(int i, int j, String str) { }

  // staticファクトリーメソッド
  // 好きなメソッド名を付けることができたり、同じ引数のメソッドだけど違う結果がほしい時にも便利
  public static factoryMethod1(int i, int j, String str) { return XXX; }
  public static factoryMethod2(int i, int j, String str) { return XXX; }
  • staticファクトリーメソッドなら、新たなオブジェクトを生成することが必要ない。

    • immutableなオブジェクトを生成したいときにも良い
    • パフォーマンスが大幅に向上することも
  • コンストラクタと異なり、メソッドの戻り値型の任意のサブタイプのオブジェクトも戻り値に使える。

  • パラメータ化された型のインスタンス生成の面倒さを低減できる。

    • Java 7からはダイアモンド構文があるので、staticファクトリーメソッドじゃなくていいかも。
// "<String, List<String>>"って書くのがめんどい
Map<String, List<String>> map = new HashMap<String, List<String>>();

// Java 7ならダイアモンド構文がある!
Map<String, List<String>> map =  new HashMap<>();

// staticファクトリーメソッドを使えば、上の冗長だった文が簡潔に書ける
public static <K, V> HashMap<K, V> newInstance() {
  return new HashMap<K, V>();
}
Map<String, List<String>> map = HashMap.newInstance();

staticファクトリーメソッドの欠点

  • public or protectedのコンストラクタを持たないクラスのサブクラスを作れない。

  • 他の普通のstaticメソッドと区別がつきづらい。

    • staticファクトリーメソッドの一般的な命名・使用用途は次
      • valueOf / of:
      • getInstance
      • newInstance
      • getType
      • newType

newInstance()ってのはよく見る気がするし、メソッドチェーンぽくインスタンス生成できるのは良さげだと思った。

項目2 数多くのコンストラクタパラメータに直面した時にはビルダーを検討する

  • テレスコーピングコンストラクタ・パターンだと、引数の種類が多すぎると対処するのが大変。
public class Facts {
  private final int calories; // 必須
  private final int fat;      // オプション
  private final int sodium;   // オプション

  // コンストラクタがパターンごとに必要になってしまう
  // また、引数の順序が難しい
  public Facts(int calories) {
    this(calories, 0, 0);
  }
  public Facts(int calories, int fat) {
    this(calories, fat, 0);
  }

  public Facts(int calories, int fat, int sodium) {
    this.calories = calories;
    this.fat = fat;
    this.sodium = sodium;
  }
}

// colaインスタンスの生成
Facts cola1 = new Facts(100, 50, 20);  // {calories, fat, sodium} = {100, 50, 20}
Facts cola2 = new Facts(100, 50);      // {calories, fat, sodium} = {100, 50, 0}
Facts cola3 = new Facts(100);          // {calories, fat, sodium} = {100, 0, 0}
...
  • Java Beansパターンだと、生成の過程で不整合な状態ができてしまうことがある。
public class Facts {
  private int calories = 0;
  private int fat = 0;
  private int sodium = 0;

  // コンストラクタは空で引数もなし
  public Facts() {}

  // Setterで処理
  public void setCalories(int val) { this.calories = val; }
  public void setFat(int val) { this.fat = val; }
  public void setSodium(int val) { this.sodium = val; }
}

// colaインスタンスを生成し、その後Setterで状態を与える
Facts cola = new Facts();
cola.setCalories(100);
cola.setFat(40);
...
  • ビルダーパターンで書くと
public class Facts {
  private final int calories; // 必須
  private final int fat;      // オプション
  private final int sodium;   // オプション

  public static class Builder {
    // 必須
    private final int calories;

    // オプションはデフォルト値で初期化しておく
    private int fat = 0;
    private int sodium = 0;

    // 必須パラメータはコンストラクタで代入
    public Builder(int calories) {
      this.calories = calories;
    }

    // オプションパラメータは好きなだけ
    public Builder fat(int val) {
      this.calories = val; return this;
    }
    public Builder sodium(int val) {
      this.sodium = val; return this;
    }

    public Facts build() {
      return new Facts(this);
    }
  }

  private Facts(Builder builder) {
    this.calories = builder.calories;
    this.fat = builder.fat;
    this.sodium = builder.sodium;
  }
}

// colaインスタンスの生成
Facts cola1 = new Facts.builder(100).fat(50).sodium(20).build();
Facts cola2 = new Facts.builder(100).fat(50).build();

ビルダーパターンはいい感じだけど、記述量が結構増えてしまうので引数が多い状況に使うのが良さそう

テレスコーピングコンストラクタ・パターンやJavaBeansパターンよりはかなり安全。


  • staticファクトリーメソッドは、たまに作っていたけど役割とか利点を理解していたわけではなかったので勉強になった。
  • ビルダーパターンはRubyとかPythonメソッドチェーンみたいに書けて、個人的にはめちゃ良いと思った。

Minicondaを試そうとしたが

普段、PythonをHomebrewでインストールしたpyenvで使っているのですが、ふとpyenv install -lを見てみたら色々なパッケージがありました。

$ pyenv install -l
Available versions:
  2.4.0
...           # ふつうのPython2系
  2.7.7

  3.0.1
...           # ふつうのPython3系
  3.4.1

  anaconda-1.4.0
...           # 数値計算ライブラリが最初から入ってるPython
  anaconda-1.8.0

...

  miniconda-2.2.2
...           # なんだこれ?
  miniconda3-3.4.2

...

どうやら、MinicondaというのはPython数値計算のライブラリを使うためのパッケージのようですが、Anacondaと違って、あとからライブラリを選んで入れるようでした。

http://conda.pydata.org/miniconda.html

そこでせっかくなので、試しに入れてみました。


まず、pyenvでMinicondaの最新版を入れます

$ pyenv install miniconda-3.4.2
$ pyenv global miniconda-3.4.2
$ pyenv rehash

(一度シェルを開き直す)

$ python --version
Python 2.7.7 :: Continuum Analytics, Inc.


$ conda list
# packages in environment at /Users/rkmathi/.pyenv/versions/miniconda-3.4.2:
#
conda                     3.5.5                    py27_0
openssl                   1.0.1h                        0
pip                       1.5.6                    py27_0
pycosat                   0.6.1                    py27_0
python                    2.7.7                         0
pyyaml                    3.11                     py27_0
readline                  6.2                           2
requests                  2.3.0                    py27_0
setuptools                3.6                      py27_0
sqlite                    3.8.4.1                       0
tk                        8.5.15                        0
wsgiref                   0.1.2                     <pip>
yaml                      0.1.4                         1
zlib                      1.2.7                         1


$ conda install numpy
Fetching package metadata: ..
Solving package specifications: .
Package plan for installation in environment /Users/rkmathi/.pyenv/versions/miniconda-3.4.2:

The following packages will be downloaded:

    package                    |            build
    ---------------------------|-----------------
    numpy-1.8.1                |           py27_0         3.0 MB

The following packages will be linked:

    package                    |            build
    ---------------------------|-----------------
    numpy-1.8.1                |           py27_0   hard-link

Proceed ([y]/n)? yes

Fetching packages ...
numpy-1.8.1-py 100% |#######| Time: 0:00:46  67.81 kB/s
Extracting packages ...
[      COMPLETE      ] |#######| 100%
Linking packages ...
[      COMPLETE      ] |#######| 100


$ conda list
# packages in environment at /Users/rkmathi/.pyenv/versions/miniconda-3.4.2:
#
...
numpy                     1.8.1                    py27_0
...

こんなかんじで、とりあえずNumPyを入れるところまで動かしました。

次に、インストールしたパッケージを使って環境を作ります。

virtualenvwrapperみたいなかんじですが、環境を作るときの入れたいパッケージを自分で選び、足りない場合はダウンロードからしてくれます。

例として、Numpy 2.1.0とIPythonをインストールしたnumpy21という名前の環境を作ってみます。

$ conda create -n numpy21 ipython numpy=2.1.0
Fetching package metadata: ..
Solving package specifications: .
Package plan for installation in environment /Users/rkmathi/.pyenv/versions/miniconda-3.4.2/envs/numpy21:

The following packages will be linked:

    package                    |            build
    ---------------------------|-----------------
    ipython-2.1.0              |           py27_2   hard-link
    numpy-1.8.1                |           py27_0   hard-link
    openssl-1.0.1h             |                0   hard-link
    python-2.7.7               |                0   hard-link
    python.app-1.2             |           py27_2   hard-link
    readline-6.2               |                2   hard-link
    sqlite-3.8.4.1             |                0   hard-link
    tk-8.5.15                  |                0   hard-link
    zlib-1.2.7                 |                1   hard-link

Proceed ([y]/n)? yes

Linking packages ...
[      COMPLETE      ] |######| 100%
#
# To activate this environment, use:
# $ source activate numpy21
#
# To deactivate this environment, use:
# $ source deactivate
#


$ source activate numpy21

しかし、何故か自分の環境だとactivateした瞬間にシェルごと落ちました(;´Д`)

ナンデー