読者です 読者をやめる 読者になる 読者になる

LoL/LJL好きのエンジニアのブログ

技術的な話やら、最近はLoLやLJLの話など。

東銀座の中華料理屋「ブルーリリー」のランチ麻婆豆腐がおいしかった

先日、ブルーリリーの麻婆豆腐が美味しいという話を聞き、ランチに麻婆豆腐を食べに行ってきました。

https://tabelog.com/tokyo/A1301/A130101/13138046/

「餃子が美味しい店だけど、麻婆豆腐も美味しいよ」という話を聞き、麻婆豆腐を食べに行きました。後日餃子と元祖担々麺も食べに行きました。 *1

店の雰囲気や接客

店は広くてそこそこ綺麗で、お昼時はそれなりに人がいます。

接客に関してはハッキリいってかなり微妙と言わざるを得ません。 ほんとに必要最低限といった接客で、他の銀座の店と比べると店員の態度はそこまでよくありません(声が小さかったり)。 僕達が行った時は混雑時を外したので、お昼のピーク時間帯あたりの接客はさらに微妙になる可能性があります。 接客には期待しないほうがいいです。その代わり値段が安いので諦めましょう。

注文してから料理が出て来るまではかなりスムーズです。

メニュー

麻婆豆腐

f:id:yoshiki_utakata:20161228122051j:plain

いろいろ食べましたが、僕は麻婆豆腐が一番美味しいと思いました。中辛と大辛があるのでとりあえず中辛を頼んだのですが、かなり辛かったです。辛いものが少しでも苦手な人は避けたほうがいいです。大辛は辛いものが相当好きじゃないと厳しいと思います。価格は980円。銀座にしてはリーズナブルです。

大餃子定食

f:id:yoshiki_utakata:20161228122257j:plain

大餃子定食は6個910円と、8個1000円があります。手前が僕の餃子6個、奥が友人の餃子8個。写真では伝わりづらいかもしれないですが、餃子1つがかなり大きいので、僕は6個で十分でした。中身がぎっしり詰まっていて、非常に美味しいです。こちらも食べてみる価値はあると思います。

元祖担々麺

f:id:yoshiki_utakata:20161228122709j:plain

汁なしの担々麺です。汁なし担々麺的なものは人生で初めて食べたのですが、思ったほど辛くなかったのが残念でした。

ということで

僕のオススメは麻婆豆腐です。機会があれば食べに訪れてみてください。

*1:全部ランチ時間帯に食べに行きました

LGTMoonの画像のレスポンスヘッダにCache-Controlを追加した

LGTMoonとは

LGTM画像を簡単に作れるサービスです。

LGTMoon - 最もシンプルなLGTM画像ジェネレーター

LGTMoonの画像保存/配信の仕組み

LGTMoonは画像をバイナリにしてPostgreSQLのImageテーブルに保存しています。

画像に対するリクエストを受けた場合は (例: http://lgtmoon.herokuapp.com/images/2045Scalaでこのリクエストを受け、DBからバイナリを読み出して返しています。 *1

class ImageBinaryController extends Controller {
  /** idを受け取り画像のバイナリデータを返す */
  def image(id: Long)  = Action.async { request =>
    // DBから引っ張ってくる
    ImageRepository.image(id).map {
      case Some(image) => {
        image.bin match {
          case Some(bin) => {
            // image/png としてレスポンスを返す
            Result(
              header = ResponseHeader(200),
              body = Enumerator.fromStream(new ByteArrayInputStream(bin))
            ).withHeaders(CONTENT_TYPE -> "image/png")
          }
          case None => NotFound("Not Found")
        }
      }
      case None => NotFound("Not Found")
    }
  }
}

フロントでの「最近の画像」表示の仕組み

フロントではvue.jsを使い、最近の画像一覧取得API(Recent API)を叩いて返ってきた結果をDOMに落とし込んでいます。 Recent APIは最新20枚の画像のURLを返すので、10秒に1回このRecent APIを叩き、結果をそのままvue.jsにかませてDOMを表示しています。

つまり、10秒に1回、imageタグを一旦全部消して、Recent APIを叩き、imageタグを追加、というステップを行っています。

レスポンスヘッダのCache-Controlについて

さて、いままで画像のレスポンスのヘッダにはCache-Controlは付けていませんでした。Cache-Controlとは キャッシュについて整理してみた - Qiita あたりを参考にしていただければわかります。ブラウザ側に「この画像はキャッシュしないでくれ」「この画像は1時間までならキャッシュしていいよ」などと伝えることができます。

Cache-Control を指定していなかった場合の問題

Cache-Controlを指定していなかった場合、キャッシュの動作について、ブラウザごとに細かい動作の違いがありました。

Google Chrome

Google Chrome において、Recent APIを叩いた結果同じ画像が存在した場合、画像へのリクエストは発生しません。

f:id:yoshiki_utakata:20161222163548p:plain

Safari

今回問題になったのはSafariでした。Safariにおいて、Recent APIを叩いた結果同じ画像が存在した場合でも、画像へのリクエストが発生します。 つまり、10秒に1回、画像20枚分のリクエストが発生することになります。

本当の原因はSafariの実装を知らなければ分かりませんが、おそらく、Cache-Controlを指定しない場合、Safariは画像をいい感じにキャッシュしてくれないのかなーという感じです。

Cache-Control を Scala Play で指定する

そこで、Cache-Controlで、画像を1時間キャッシュしろという命令をレスポンスヘッダに含めました。 *2 Scala Play で Cache-Control をレスポンスヘッダに含める方法は以下の通りです。

/** 画像のバイナリデータを返すコントローラー */
class ImageBinaryController extends Controller {
  /** idを受け取り画像のバイナリデータを返す */
  def image(id: Long)  = Action.async { request =>
    ImageRepository.image(id).map {
      case Some(image) => {
        image.bin match {
          case Some(bin) => {
            Result(
              header = ResponseHeader(200),
              body = Enumerator.fromStream(new ByteArrayInputStream(bin))
            ).withHeaders(
              CONTENT_TYPE -> "image/png",
              CACHE_CONTROL -> "max-age=3600") // 1時間キャッシュしろ
          }
          case None => NotFound("Not Found")
        }
      }
      case None => NotFound("Not Found")
    }
  }
}

これを行うことにより、Safariでも画像のキャッシュが効くようになり、Recent APIを叩いた後での画像へのリクエスト数が激減しました。 さらに、Chromeなどでもページをリロードした際には積極的にキャッシュが使われるようになります。

f:id:yoshiki_utakata:20161222164417p:plain

今回の画像は一度作られたら変わらないものなので、キャッシュ時間をさらに長くすることも可能です。

まとめ

HTTPレスポンスヘッダーのCache-Controlについて学んだお話でした。

Ubuntuにdockerをインストールする

はじめに

JenkinsとかGitなどを、Docker上で動かしたいため、家にあるUbuntuサーバーにDockerを入れたいと思います。

環境

$ cat /etc/lsb-release
DISTRIB_ID=Ubuntu
DISTRIB_RELEASE=14.04
DISTRIB_CODENAME=trusty
DISTRIB_DESCRIPTION="Ubuntu 14.04.2 LTS"

Dockerのインストール

以下に従って行います

docs.docker.com

aptのupdate

$ sudo apt-get update
...
以下の鍵 ID に対して利用可能な公開鍵がありません:
1397BC53640DB551

えぇ...

とりあえず以下のリンクを参考に

abyssluke.hatenablog.com

$ sudo apt-key adv --recv-keys --keyserver keyserver.ubuntu.com 1397BC53640DB551

としてから再開

$ sudo apt-get update
$ sudo apt-get install apt-transport-https ca-certificates
$ sudo apt-key adv --keyserver hkp://ha.pool.sks-keyservers.net:80 --recv-keys 58118E89F3A912897C070ADBF76221572C52609D

今回は Ubuntu 14.04 なので、以下のコマンドを実行。

$ echo "deb https://apt.dockerproject.org/repo ubuntu-trusty main" | sudo tee /etc/apt/sources.list.d/docker.list
$ sudo apt-get update

以下のコマンドを実行して、インストールされるバージョン候補が表示されたらたぶんここまでは大丈夫です。

$ apt-cache policy docker-engine

Dockerインストールの準備

$ sudo apt-get install linux-image-extra-$(uname -r) linux-image-extra-virtual

Dockerのインストール

$ sudo apt-get install docker-engine

Dockerの起動

$ sudo service docker start
start: Job is already running: docker

Hello World でインストールされていることを確認

$  sudo docker run hello-world
Unable to find image 'hello-world:latest' locally
latest: Pulling from library/hello-world
c04b14da8d14: Pull complete
Digest: sha256:0256e8a36e2070f7bf2d0b0763dbabdd67798512411de4cdcf9431a1feb60fd9
Status: Downloaded newer image for hello-world:latest

Hello from Docker!
This message shows that your installation appears to be working correctly.

次回

次回はDockerを試す意味も含めてJenkinsをインストールしてみたいと思います。

GitHubのgistに軽度のバグを見つけてバグ報告を出した話

がいよう

先日、GitHubのgistを使っていてバグを見つけました。ググってみたら同じバグを踏んでいる人はいなかったみたいなので *1 、バグ報告してみました。その結果、ちゃんとGitHubから返信がきたため、ここでは、どうやってバグ報告したかと、ほかの人が同じような報告をしないように *2 バグについてまとめておきます。

バグの内容

スクリーンショットと詳細な説明(下手な英語)は以下のリポジトリにアップロードしてあります。

github.com

  1. gistを新規作成します。Add fileをクリックしてファイルを2つにします。仮にファイル名を01.md, 02.mdとします。01.mdと02.mdの中身を同じにして保存します。
  2. 保存したgistのeditボタンを押します。
  3. 02.mdを03.mdにリネームして保存します。
  4. リネームしたかったのですが、02.mdも03.mdも両方残った状態になります。

01.mdと02.mdの中身が同じでないと発生しないようです。明らかにバグっぽい挙動をしています。

報告方法

セキュリティ的なバグの場合

GitHub バグ 報告 とかでググると、以下の記事がまず見つかると思います。

GitHubにバグ報告して賞金$500を頂いた話

ただし、これはセキュリティ的なバグを見つけたときのやつっぽいですね。もしかしたら僕の発見したバグからセキュリティ的なやつにつなげられるのかもしれませんが、ぱっと僕は思いつきませんでした。

軽度のバグの場合

Contact GitHubを使ってコンタクトをとってみて報告しました。参考にしたのは以下のブログです。

giginet.hateblo.jp

内容としては、「バグの内容」に書いたようなことをそのまま英語で書いたうえで *3 、「スクリーンショットを以下のところにアップロードしておきました」として、 https://github.com/yoshikyoto/github-gist-bug のURLを添えておきました。

そしたら1日くらいで以下のような返信が帰ってきました。  

Thanks for the detailed report! That's really interesting behavior and seems like a bug to me - we can't promise an ETA but we'll ask our engineers to take a look.

簡単に訳すと「詳細な報告ありがとう!面白いバグですね。修正をお約束することはできませんがエンジニアには伝えておきます」という感じですかね。返信が返ってきたってことは、セキュリティに関係ない軽度なバグだったらこのフォームで伝えたら問題ないということですかね。

おわりに

という感じで、これで一旦決着はついたのでここまでの流れを書きました。 暇があったらこのバグについてもっと詳しく見ていきたいですね。 修正にも期待しましょう。

*1:限定的な状況でしか起こらないバグだからだと思います

*2:今回の件については、以下に書くようにすでに返信も頂いており、向こうにはすでにバグとして伝わったと思います

*3:下手な英語でも向こうは読み取ってくれるので、伝える気持ちが大事。

自宅に開発環境を組み立てたい - 開発環境を整える連載 Part1

自宅でWebアプリ開発をしたくて、開発環境が欲しくなったので、組み立てていく連載です。今回の連載で作りたい開発環境は以下の通りです

  • Jenkins
  • GitBucketやBitBucket、GitLab的なソースコード管理システム
  • アプリケーション開発環境用サーバー

そのために、サーバーに仮想環境をいくつか載せて、その上でJenkinsやアプリケーション開発用サーバーを載せていきます。

仮想環境としては、基本的にはDockerを使っていきたいですが、世の中全てかDockerなわけではありません。Ansibleなんかで構成管理したい場合もあるでしょう。そこで、Vagrant&Ansibleな環境も欲しいです。ちょうど手元に物理サーバーが2台あるため、片方にDockerを、片方にVagrantを載せたいと思います。

まずはDocker環境を作って、その上にGitBucketを乗せるところから始めようかなと思うのですが、その前に、サーバーを2台用意するために、Mac mini Late2012モデルのメモリを増設したので、次回はその話を書こうかと思います。