oinume journal

Scratchpad of what I learned

DMM英会話でお気に入りの先生の空きレッスンがあった時にメール通知するlekcijeというサービスを作った

www.lekcije.com

lekcijeという、DMM英会話で講師に空きレッスンがあった時にメール通知するサービスを作った。もともとは下記で書いたものがベースになっていて、これに画面を付け足したという感じ。毎日家に帰ってから自分の空き時間でチマチマ作っていたので半年ぐらいかかってしまった。

oinume.hatenablog.com

作った動機としては

  • DMM英会話はレッスンが終わらないと次の分の予約ができない
  • 人気の講師はすぐ予約が埋まってしまう
  • でも意外とキャンセルが出るので、それを逃したくない

という感じ。もちろんお金をかければ1枚500円もするレッスンチケットを買いまくって予約するということはできるのだろうけど、さすがにそれは金銭的につらかったので技術で解決しようという試み。

実装に関して

本当はReactとかも使いたかったんだけど、どうしても時間が取れなくてSPA的なモノは諦めて、サーバーサイドでHTMLを生成するというオールドタイプな実装になっている。Herokuを使っているのでアメリカの東海岸からHTMLが配信されるのがつらいけど、静的ファイルはHTTP2を使って配信するようにしてパフォーマンス面には気を遣った。

久しぶりにWebサービスを作ったのだけど、普段の仕事ではサーバーサイドのコードしか書かないので、ロゴ作ったりキャッチコピー考えたりすることはいい勉強になった。プロの人はすごいなぁと思うばかりです。というわけで、DMM英会話をやっている人がいたらぜひ使ってみて下さい。

使った技術

  • HTTP2
    • Let's encryptでSSL証明書を取得
  • Frontend
    • bootstrapだと素っ気ないので、bootswatchを使った
    • ビルドにはWebpack使った(つらい)
  • Server (Go)
    • Web Applicaton Framework: gojiを使ったけど、素のnet/httpでもよかったかもしれない。もはやルーティング回りしかgojiを使っていない
    • ORMapper: gorm (つらい)
    • Vendoring: glide
    • Logging: uber-go/zap
    • Scraping: xmlpath
      • goqueryのコールバックスタイルがどうも好きになれなかったので。
    • Hot reloading: reflex
      • 開発時のホットリローディング
  • Database: MySQL 5.7
    • Database migration: goose使ったけど、sql-migrateにする予定
  • E2E test
    • agouti: Selenium WebDriver的なヤツ
  • Nginx: 静的ファイルの配信
  • メール送信: Sendgrid
  • Heroku
  • ngrok
    • スマホで動作確認したい時に便利過ぎた

コードリーディングのためのIntelliJ IDEAショートカット

自分がソースコードを読む時によく使っているIntelliJのショートカット集。もちろんWebStormやAndroid StudioなどIntelliJシリーズなら全部使えるはず。他にもこんなのがあるよ、というのがあればコメントとかTwitterで教えてもらえると嬉しい。ちなみにショートカットのキーバインドはMac前提で書いてます。IntelliJのバージョンは2016.2

F1: Quick Documentation

キャレット上のシンボル(変数/関数)のドキュメントをポップアップで表示。自分は「これなんだろう?」って気になったらとりあえずF1押してる。

Opt + Space: Quick Definition

Quick Documentationに加えて、キャレット上のシンボルのソースコードも含めて下記のようにポップアップで表示してくれる。

IntelliJ IDEA Quick Definition

Cmd + P: Parameter Info

キャレット上の関数のパラメータ情報を表示。「この関数にこの値を渡しているけど、これはどういう引数なんだっけ?」を確認する時に使ってる。

Cmd + B: Declaration

キャレット上のシンボルの定義元にジャンプする。

Opt + Cmd + ←: Back

Undo last navigation operation. 最後に使ったナビゲーションの操作を一つ戻る。自分は

  • Cmd + Bで定義元にジャンプ
  • 確認したらOpt + Cmd+←で戻る

という感じでソースを読んでる。Ctrl + TabでSwitcherで戻るというやり方もあるそうなのでお好みで。

Opt + F7: Find Usages

キャレット上のシンボルを使用している箇所を表示する。例えば以下のスクショだと、errors.Internalfという関数を使っている箇所を表示している。

IntelliJ IDEA

Cmd + -: Collapse

キャレット上の関数などを折り畳む

Cmd + +: Expand

キャレット上の関数などを展開する(折り畳むのの反対)

Ctrl + Opt + h: Call Hierarchy

キャレット上の関数の呼び出し階層を表示する。その関数がどのように使用されているのかがわかるのでかなり重宝する。

余談

同僚に「Help -> Productivity Guide で使ったこと無い機能の一覧を眺めてみては」と言われて試したところ、自分が使ったことのない機能がいっぱいあった。何回ぐらいその機能使ったか、最後に使ったのはいつかを出してくれるなんて、なんて親切なんだろう。

IntelliJ IDEA Productivity Guide

あと 今井さんにQuick DefinitionとSwitcherを教えてもらいました。ありがたや〜。

次回予告

コードを書くためのIntelliJ IDEAショートカット、という記事を書く予定。

Android Studio本格活用バイブル ~効率的にコーディングするための使い方

Android Studio本格活用バイブル ~効率的にコーディングするための使い方

VPSをConoHaからVultrにお引越し

昔はブログ用のWordPressホスティングしていたVPS、今ではもうリダイレクトするためだけにNginxを動かしているだけなので、$5で1CPU, 768MBとそこそこのスペックなVultrに引っ越してみた。以下はUNIX Benchの結果。たいしたことしなければ速度的な不満はないし、ConoHaみたいにメンテナンスもない気がするので、わりとオススメ。まだ2ヶ月ぐらいしか使ってないけど。もちろんTokyoリージョンもあります。

ちなみにこのリンクを踏んでから登録してもらうと、$20分の無料枠がもらえるのよかったらどうぞ。(そして私には$30入る)

========================================================================
   BYTE UNIX Benchmarks (Version 5.1.3)

   System: <name>: GNU/Linux
   OS: GNU/Linux -- 4.4.0-24-generic -- #43-Ubuntu SMP Wed Jun 8 19:27:37 UTC 2016
   Machine: x86_64 (x86_64)
   Language: en_US.utf8 (charmap="UTF-8", collate="UTF-8")
   CPU 0: Virtual CPU 714389bda930 (4800.0 bogomips)
          x86-64, MMX, Physical Address Ext, SYSENTER/SYSEXIT, SYSCALL/SYSRET
   21:57:06 up  7:49,  1 user,  load average: 0.02, 0.03, 0.05; runlevel 5

------------------------------------------------------------------------
Benchmark Run: Sat Jun 18 2016 21:57:06 - 22:24:56
1 CPU in system; running 1 parallel copy of tests

Dhrystone 2 using register variables       29026791.2 lps   (10.0 s, 7 samples)
Double-Precision Whetstone                     2128.1 MWIPS (9.9 s, 7 samples)
Execl Throughput                               4333.0 lps   (30.0 s, 2 samples)
File Copy 1024 bufsize 2000 maxblocks       1177018.5 KBps  (30.0 s, 2 samples)
File Copy 256 bufsize 500 maxblocks          313427.7 KBps  (30.0 s, 2 samples)
File Copy 4096 bufsize 8000 maxblocks       2236331.1 KBps  (30.0 s, 2 samples)
Pipe Throughput                             2264531.3 lps   (10.0 s, 7 samples)
Pipe-based Context Switching                 346957.1 lps   (10.0 s, 7 samples)
Process Creation                              11074.8 lps   (30.0 s, 2 samples)
Shell Scripts (1 concurrent)                   7970.2 lpm   (60.0 s, 2 samples)
Shell Scripts (8 concurrent)                   1059.4 lpm   (60.0 s, 2 samples)
System Call Overhead                        3657643.4 lps   (10.0 s, 7 samples)

System Benchmarks Index Values               BASELINE       RESULT    INDEX
Dhrystone 2 using register variables         116700.0   29026791.2   2487.3
Double-Precision Whetstone                       55.0       2128.1    386.9
Execl Throughput                                 43.0       4333.0   1007.7
File Copy 1024 bufsize 2000 maxblocks          3960.0    1177018.5   2972.3
File Copy 256 bufsize 500 maxblocks            1655.0     313427.7   1893.8
File Copy 4096 bufsize 8000 maxblocks          5800.0    2236331.1   3855.7
Pipe Throughput                               12440.0    2264531.3   1820.4
Pipe-based Context Switching                   4000.0     346957.1    867.4
Process Creation                                126.0      11074.8    879.0
Shell Scripts (1 concurrent)                     42.4       7970.2   1879.8
Shell Scripts (8 concurrent)                      6.0       1059.4   1765.7
System Call Overhead                          15000.0    3657643.4   2438.4
                                                                   ========
System Benchmarks Index Score                                        1576.9

ちなみに以前使っていたConoHaのUNIXベンチ

HerokuでMySQL 5.7系を使う方法

JawsDBというaddonを使うともれなく5.7系のMySQLが使える。2016年9月現在だと5.7.11。

elements.heroku.com

HerokuのデフォルトのデータベースはそもそもPostgreSQLで、MySQLを使いたい場合はこのJawsDBもしくはClearDBの2者択一なんだけど、ClearDBの方は5.5系しか使えない。安定してる5.5を取るか、最新版の5.7のどっちがいいかは悩ましいところだけど...

3ヶ月ぶりに書いたブログ記事がこれかよ...!

Arguments to defered functions are evaluated when the defer executes

The arguments to the deferred function (which include the receiver if the function is a method) are evaluated when the defer executes, not when the call executes.

Effective Go - The Go Programming Language

I sometimes make a mistake that defered functions are evaluated when the function is called but it’s wrong. Here is an example.

package main

import (
        "fmt"
        "time"
)

type wrapped func()

func main() {
        wrapper(func () {
                time.Sleep(time.Second * 3)
                fmt.Println("Hello")
        })
}

func wrapper(f wrapped) {
        fmt.Println("wrapper() start: ", time.Now().UTC())
        defer instrument(time.Now().UTC())
        f()
        fmt.Println("wrapper()   end: ", time.Now().UTC())
}

func instrument(start time.Time) {
        fmt.Println("instrument():    ", start)
}
$ go run defer.go
wrapper() start:  2016-05-23 07:28:37.474091714 +0000 UTC
Hello
wrapper()   end:  2016-05-23 07:28:40.474272645 +0000 UTC
instrument():     2016-05-23 07:28:37.474139821 +0000 UTC

If defer functions are evaluated at call time, instrument() time must be 3 seconds later.