■
クラスの責務を明確にする、単一にするみたいな話があるけど、なんかの資料みたいなものに関しても色んな責務をもたせると、ただでさえ怠い作業がもっと怠くなって全部中途半端になってしまう。この資料ではこれについての説明だけはちゃんと書いて他は書かないみたいな感じにしたほうが良い。
zshの起動はやくした
zshrcの読み込みに時間がかかっていたのでそれの短縮。
ちまちま他のとことかで無駄だったとこ削ったりしたんだけどほぼ関係なかった。
Functional Programming Principles in Scala
https://www.coursera.org/course/progfun
をやってるんだけど、結構面白い。この講義自体は http://shanon-tech.blogspot.jp/2013/04/top5.html で知った。
プログラミングパラダイムの話で
- imperative programming
- functional programming
- logic programming
の3つがあって
- object-oriented programming
はその3つとは直交する。で、ScalaではFPとOOPを混ぜたみたいなことを言っていた。
JVM上で動くしJavaの人が慣れやすいように〜とかってそういう感じだったのかなーと勝手に思ってたんだけど、そういう意思のもと入れたものだったんだなと知った。このへんでScalaに興味出てきた。ぶっちゃけscaleさせたいようなweb serviceを運用してるわけでもなく、scalability的な文脈ではさほど興味を持ってなかった。
また、SCIP(途中で投げ出してたのを再開中...)の例題とかが出てくるんだけど、課題にはテストがついてたり、動画の途中にQuizが出たり、一人で本読むより飽きにくいと思う。
あとはScala IDEのworksheetっていうのが柔軟なREPLみたいな感じで面白いし、Scalaで開発やりたい感じ出てきた。最近ChromeとIRC ClientとTerminal以外立ち上げずそこで完結するように頑張るみたいな原始的なことをしているおかげか、IDEもサクサク動いた。
dotCloud製Linux Container, Docker触ってみた
とりあえず、VM一個立てて、rackupしようと思った。
digitaloceanのvpsで試していたんだけど、なんかおかしいと思ったらkernelのバグの影響だったようで、3.5.0-21以上を使ったほうが良さそう。 https://github.com/dotcloud/docker/issues/25
ちなみにdigitaloceanのvpsでは
$ uname -r 3.5.0-17-generic
なので、Vagrantで適当なUbuntuのVM立てた。
def v10(config) config.vm.box = "ubuntu-quantal" config.vm.box_url = "http://cloud-images.ubuntu.com/quantal/current/quantal-server-cloudimg-vagrant-amd64-disk1.box" end Vagrant::VERSION < "1.1.0" and Vagrant::Config.run do |config| v10(config) end Vagrant::VERSION >= "1.1.0" and Vagrant.configure("1") do |config| v10(config) end Vagrant::VERSION >= "1.1.0" and Vagrant.configure("2") do |config| config.vm.provider :virtualbox do |vb| config.vm.box = "ubuntu-quantal" config.vm.box_url = "http://cloud-images.ubuntu.com/quantal/current/quantal-server-cloudimg-vagrant-amd64-disk1.box" end end
$ uname -r 3.5.0-26-generic
Install
$ sudo apt-get install lxc wget bsdtar curl $ sudo apt-get install linux-image-extra-`uname -r` $ wget http://get.docker.io/builds/$(uname -s)/$(uname -m)/docker-master.tgz $ tar -xf docker-master.tgz
基本(READMEに書いてる)
僕は当初Containerとimageを混同していて、$ sudo ./docker pull IMAGE_NAME
でVMのようなものを作っているのかと思ってたが、そうではなくimageはコンテナのひな形、インスタンスに対するクラスのようなもの。また、runで新しくコンテナを作ってコマンドを実行しても、コマンドが終了すればコンテナは消える。
# イメージのダウンロード $ sudo ./docker pull IMAGE_NAME # コンテナ上でコマンドを実行 $ sudo ./docker run -i -t IMAGE_NAME COMMAND # shell立ち上げることで、普通にそのコンテナにログインして作業みたいなこともできる $ sudo ./docker run -i -t IMAGE_NAME /bin/bash # Container の IDに対して操作出来る $ (sudo ./docker -d || echo "Docker daemon already running") & $ CONTAINER=$(docker run -d base /bin/sh -c "while true; do echo Hello world; sleep 1; done") $ echo $CONTAINER 2fa7019f6fdf3e85c249fa2c2eef093c294fc8c0d5262377e9754f491a3dc2e1 $ docker logs $CONTAINER 2013/03/29 07:33:54 docker logs 2fa7019f6fdf3e85c249fa2c2eef093c294fc8c0d5262377e9754f491a3dc2e1 Hello world Hello world Hello world Hello world Hello world Hello world $ docker logs $JOB 2013/03/29 07:33:56 docker logs 2fa7019f6fdf3e85c249fa2c2eef093c294fc8c0d5262377e9754f491a3dc2e1 Hello world Hello world Hello world Hello world Hello world Hello world Hello world Hello world $ docker kill $JOB 2013/03/29 07:34:23 docker kill 2fa7019f6fdf3e85c249fa2c2eef093c294fc8c0d5262377e9754f491a3dc2e1 # runはコンテナを新しく起動してコマンドを実行するもので、 # 永続的なコンテナを作るものではないので、コマンドの実行が終わると # コンテナは消える。 # コマンドの実行によりコンテナに与えた変更はcommitすることにより # 新たなimageが作成できる。 $ sudo ./docker run -i -t base bash root@ea19df583e44:/# adduser toqoz Adding user `toqoz' ... Adding new group `toqoz' (1000) ... Adding new user `toqoz' (1000) with group `toqoz' ... Creating home directory `/home/toqoz' ... Copying files from `/etc/skel' ... Enter new UNIX password: Retype new UNIX password: passwd: password updated successfully Changing the user information for toqoz Enter the new value, or press ENTER for the default Full Name : Room Number : Work Phone : Home Phone : Other []: Is the information correct? [Y/n] root@ea19df583e44:/# su toqoz bash: no job control in this shell $ exit exit root@ea19df583e44:/# exit exit $ sudo ./docker run -i -t base bash 2013/03/29 08:08:37 docker run -i -t base bash bash: cannot set terminal process group (-1): Inappropriate ioctl for device bash: no job control in this shell root@b612c0b3d72d:/# su toqoz Unknown id: toqoz
自分用のbase imageを作成
$ sudo ./docker pull base $ CONTAINER=$(docker run -d base apt-get install -y curl) $ docker commit -m "Installed curl" $CONTAINER $USER/sample $ docker push $USER/sample $ docker images 2013/03/29 08:16:58 docker images REPOSITORY TAG ID CREATED PARENT vagrant/sample latest c287f15311bfbb0c2e664f5e29561d5f8e03567b7a9f640140106213bbc6fa9d 45 seconds ago base:latest base latest b750fe79269d2ec9a3c593ef05b4332b1d1a02a62b4accb2c21d589ff2f5f2dc 5 days ago 27cf784147099545 base ubuntu-12.10 b750fe79269d2ec9a3c593ef05b4332b1d1a02a62b4accb2c21d589ff2f5f2dc 5 days ago 27cf784147099545 base ubuntu-quantal b750fe79269d2ec9a3c593ef05b4332b1d1a02a62b4accb2c21d589ff2f5f2dc 5 days ago 27cf784147099545 base ubuntu-quantl b750fe79269d2ec9a3c593ef05b4332b1d1a02a62b4accb2c21d589ff2f5f2dc 5 days ago 27cf784147099545 # ps でコンテナを探してattachすることもできる $ sudo ./docker ps 2013/03/29 09:12:28 docker ps ID IMAGE COMMAND CREATED STATUS COMMENT 307304dc7bd498f7ee3b8e76e3bbc492b8b1a7c698fb7e100c3b4d331e108d99 base:latest apt-get install -y r 5 minutes ago Up 5 minutes 61b385d5cd8ce70d3e6df7a256777aacdebf3cebb483285f50f006d6f0c17e00 base:latest echo hello 21 minutes ago Up 21 minutes 7ddd667b4edf3c603b89027a2f2f731b64c6b34487e2a03ab96daa4af3504cbe base:latest echo hoge 24 minutes ago Up 24 minutes $ sudo ./docker attach 307304dc7bd498f7ee3b8e76e3bbc492b8b1a7c698fb7e100c3b4d331e108d99
$ sudo ./docker commit -m 'dist-updated' $CONTAINER $USER/base # sudo ./docker run some_image apt-get update && apt-get install foo が # (sudo ./docker run some_image apt-get update) && apt-get install foo みたいな感じに解釈されてしまうので、とりあえず sh -c '' で実行してる $ CONTAINER=$(sudo ./docker run -d base sh -c '\ export DEBIAN_FRONTEND=noninteractive && \ echo "deb http://archive.ubuntu.com/ubuntu quantal-updates main universe multiverse" >> /etc/apt/sources.list && \ apt-get -y update && \ apt-get -y upgrade && \ apt-get -y dist-upgrade \ apt-get install -y build-essential openssl libreadline6 libreadline6-dev curl git-core' \ ) $ sudo ./docker commit -m 'Installed build-essential openssl libreadline6 libreadline6-dev curl git-core' $CONTAINER $USER/base
自分用のbase imageをベースにruby用のimageを作る
$ CONTAINER=$(sudo ./docker run -d $USER/base sh -c '\ export DEBIAN_FRONTEND=noninteractive && \ apt-get install -y libssl-dev zlib1g-dev libyaml-dev && \ cd /tmp && \ git clone git://github.com/sstephenson/ruby-build.git && \ cd ruby-build && PREFIX=/opt/ruby-build ./install.sh && \ /opt/ruby-build/bin/ruby-build --with-open-ssl-dir=usr 2.0.0-p0 /opt/ruby2.0.0' ) $ sudo ./docker commit -m 'Installed Ruby' $CONTAINER $USER/rubybase $ sudo ./docker run $USER/rubybase env PATH=/opt/ruby2.0.0/bin:$PATH ruby -v 2013/04/01 01:19:08 docker run vagrant/rubybase env PATH=/opt/ruby2.0.0/bin:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:/usr/games:/usr/local/games ruby -v ruby 2.0.0p0 (2013-02-24 revision 39474) [x86_64-linux]
ruby用のimageをbaseにrack app用のimageを作る
$ CONTAINER=$(sudo ./docker run -d $USER/rubybase env PATH=/opt/ruby2.0.0/bin:$PATH gem install rack --no-ri --no-rdoc $ sudo ./docker commit -m 'Installed rack' $CONTAINER $USER/rackbase
rack appを起動するしてアクセスしてみる
$ CONTAINER=$(sudo ./docker run -d -p 9292 $USER/rackbase \ env PATH=/opt/ruby2.0.0/bin:$PATH \ sh -c 'rackup -b "run proc { |env| [200, { %{Content-Type} => %{text/html} }, %{Hello\n}.chars] }"' \ ) $ sudo ./docker logs $CONTAINER 2013/04/01 05:42:48 docker logs baa621dd4def [2013-04-01 05:42:38] INFO WEBrick 1.3.1 [2013-04-01 05:42:38] INFO ruby 2.0.0 (2013-02-24) [x86_64-linux] [2013-04-01 05:42:38] INFO WEBrick::HTTPServer#start: pid=5 port=9292 $ PORT=$(sudo ./docker port $CONTAINER 9292) $ HOST=$(ifconfig | grep 'inet ' | head -n1 | sed -e 's/^.*inet addr://' -e 's/ .*//') $ curl $HOST:$PORT Hello
実際にprivate paasみたいな感じで使うには
コンテナの存在をチェックして、再起動する仕組みと、ルーターを作れば、とりあえず簡素なの作れる気がした。
環境構築の自動化について
imageをpushすることも出来るので、chefなどを使った自動化というより、dockerのエコシステムの中でうまく自動化していくのがいいんじゃないかなと思ったりした。ただ現状、そのimageがどのように作られたかとかを知る術を僕は知りません。
tmux new-session or attach-session
$ tmux new-session -s SESSION_NAME || tmux attach -t SESSION_NAME
でできる
$ ([ $(tmux list-session | grep '^SESSION_NAME: ' | wc -l) -gt 0 ] && tmux attach -s SESSION_NAME) || tmux new-session -s SESSION_NAME
とかする必要なかった。
tmuxinatorっぽいことがtmuxのコマンドだけで出来る
tmuxの想像以上にコマンドからなんでも出来る感にうれしさを感じた。
tmux send-keys
でキー入力を送るみたいなことが出来て、tmux send-keys 'echo hoge' Enter
でecho hoge[Enter]
というキーを送れる、つまり任意のコマンドが実行できる。- また、
tmux command1 \; command2
という形で順番にコマンドを実行できる。
上記2つを組み合わせることでtmuxinatorでやる、windowをいくつ開いて、そこでpaneをいくつ開いて、それぞれでなんかコマンドを実行する。みたいなことが可能になる。ただ複雑になるくらいなら諦めてtmuxinator使ったりしたほうが良いとは思う。
# 今回この方法でやったこと tmux new-session \; \ new-window \; send-keys 'atig -d -h 127.0.0.1' Enter \; last-window \; \ split-window -h -l 30 \; send-keys 'clear && cat ~/.irssi/nicklistfifo' Enter \; last-pane \; \ send-keys 'clear && irssi' Enter
■
hsl(Hue, Saturation, Lightness) による指定が便利で、 scssなどで書いていると、コンパイル時RGBに直してくれるので、サポートしてないブラウザでも使えて便利。
例えば
@mixin interactive-button($hue, $saturation, $lightness) { background-color: hsl($hue, $saturation, $lightness); &:hover { background-color: hsl($hue, $saturation, $lightness * 1.15); } &:active { background-color: hsl($hue, $saturation, $lightness * 0.6); } }
みたいなmixin書いてると、Hue, Saturation, Lightnessを一つ指定するだけで、hoverした時にちょっと明るくなって、押すと暗くなるみたいなボタンを作れて便利。
色を変数に入れておくときに
$some_color_hue: なんとか; $some_color_saturation: なんとか; $some_color_lightness: なんとか; $some_color = hsl($some_color_hue, $some_color_saturation, $some_color_lightness);
みたいにしておくとそのまま使う時は $some_color
で使えるし、ちょっと暗くして使いたいときは hsl($some_color_hue, $some_color_saturation, $some_color_lightness * 0.8)
とかって感じで使えるし良い。
selfとthatについて
selfが実質予約語であるとか、Function#bindとかは無視して、変数名としてだけの話をします。
function() { // ここではその通りだと思う var self = this; // この時点ではthatではなく間違いなくthisというかself的なもんでしょ var that = this; (function() { // ここでself使ったりするの、名前的に既におかしいよね。ここではもうselfじゃないでしょ。 // ここでthatと呼ぶのはselfよりはニュアンス的に合ってると思う。 })(); }
ということでどっちもおかしい気がする。普通に具体的な名前付けるのが良いと思う。
selfのほうがーみたいな意見を見たりしましたが、変数の名前としては、どっちもどっちで微妙ですねという話。
そもそも他の慣習言語の慣習からselfとかっていうのかも知れませんが、少なくとも僕はPythonかじった程度ですが、Pythonでのselfはそのインスタンスを指し、他のオブジェクトを指すことはなかった気がしますと思います。
特に言いたいことはないです。
■
難しいかったことを「何か」によってシンプルにできるようになって、そうすると「何か」の仕組みを把握するのが難しくなって、「何か」の仕組みが簡単なものが出てきて、でもそれじゃあ難しかったことを難しいまましか出来ないよねってなって、好みと個人の置かれている環境により激しくどっちが優れているかの論争が始まり、結局論争している間に人類が滅亡する夢を見た。その前の夢はガオー氏というライオンのマフィアに追いかけられ続ける夢だった。
Smalltalkベストプラクティス・パターンを読んだ
新横浜-姫路間で運良く座れたので読んでいた。良いと思ったところとか。
Intention Revealing Selector
メソッドの名前を考えるときに、異なる実装の同じことをなすメソッドを考えてみて、それ同じ名前に出来るのであれば、十分抽象化されている。というようなことが書いてあった。指標となる例があるの嬉しかった。抽象化されているかどうかとか一人で考えていると闇の世界に入っていってよく分からなくなることがあると思う。
Direct Variable Access
インスタンス変数に直接アクセスするのは分かりやすいから、アクセサが必要ないときは直接アクセスしてもいいんじゃない?(文法的にRubyとかだとアクセサ定義したほうが変数普通に使ってるっぽいから微妙だけど)みたいなことが書いてあった。継承することのない時までいつでもアクセサ定義しなければならないみたいな呪縛から解かれるかもしれない。柔軟性と手軽さどちらかを自分で選ばないといけないが。
Role Suggesting Temporary Variable Name
変数の型と役割が分かることが重要。式をわかりやすく書けば、型を知ることができるし、それに加え名前で役割を十分に表せればよいと思う。
Collect
コレクションの各要素に処理を行いたい場合、collectで中間コレクションを作れば(そのようなメソッドを用意すれば)、コードは明瞭になる。パフォーマンスのことを気にするのは後で、問題になったときと書いてあった。リファクタリングにも書いてあったけど、きちんとわかりやすく書いたほうが、あとからパフォーマンス上の問題も発見しやすく、変更しやすい。最近は途中で思い出したようにパフォーマンスが気になり出しても、ア、今じゃないんだ、と考えるようにしている。
Guard Clause
僕はRubyでreturnを書かないようにしていたんだけど、ここに良い言葉があった。"複数のリターン文で書かれたメソッドはしばしばプログラマの意図を直接的に表すことがあります。" 途中でreturnするほうが意図に合っていれば、複数のreturnを使うのが良いかもしれない。
あと何回か読みたいと思う。
ケント・ベックのSmalltalkベストプラクティス・パターン―シンプル・デザインへの宝石集
- 作者: ケントベック,Kent Beck,梅沢真史,皆川誠,小黒直樹,森島みどり
- 出版社/メーカー: ピアソンエデュケーション
- 発売日: 2003/03
- メディア: 単行本
- 購入: 7人 クリック: 93回
- この商品を含むブログ (55件) を見る
■
これは抽象的な概念とか考え方なんだ、というように説明されているものがあるけど、具体的に解決する問題とかなぜ解決できるのか、とかがなくて良いのかどうか判断しかねるみたいな感じになることがなる。OOの話とかでも途中でそういう話題になってわからなくなるみたいなのある。本でも問題とか、なぜ解決できるかとかだけでもバカにも分かるように書いてる本は読みやすくて嬉しい感じがする。
Rack middlewareのテスト
require 'rack/test' describe Rack::HogeMiddleware do include Rack::Test::Methods subject(:response) { last_response } let(:app) do this_plugin = described_class Rack::Builder.new do use this_plugin map '/foo' do run lambda { |env| [200, {'Content-Type' => 'text/html'}, '<html></html>'] } end map '/bar' do run lambda { |env| [200, {'Content-Type' => 'text/html'}, '<body></body>'] } end end.to_app end before do get '/' end it 'なんかテスト書く' do # response.body.should # なんとか~ end end
こんな感じdummyのアプリを作ってテスト書いていけるので便利です。
Redisのソースコードをちょっと読んでみようという試み(1)
C言語でHello world以上のものを読むのは初めてだった。とりあえず実装の詳細は飛ばして、
サーバー立ち上げる -> クライアントから繋がる -> コマンドが実行される -> 書き込まれる までの関数の呼ばれる流れだけを追ってみた。
大分意図的に端折ってるし、意図せず抜けてたり間違ってたりすると思うから、間にうけないほうが良さそう
Doxygenというので、ドキュメントっぽいのを生成して、それも時々見てた。全然関係ないけどdoxygenをgui付きのオプション付けてbrewでビルドしようとしたけど、依存しているQtのビルドに時間がかかって、そのうえGUI(doxywizard)のバイナリ出来てなかった感じがして損した感じがした。
しょうがないからDoxyfile色々いじってやった。https://gist.github.com/ToQoz/5057612 途中関数のコールグラフみたいなのが出てきてる感じになったけど、色々いじってたら出てこなくなった気がする。
main initServer acceptTcpHandler(acceptUnixHandler) anetTcpAccept anetGenericAccept accept # クライアントから繋がれました~~~ acceptCommonHandler createClient # redisClient作って返す(この後こいつが色々持つ、コマンドとか) readQueryFromClient # clientからのqueryの長さとかチェックしたりする processInputBuffer # request typeとか決定したり(決まって無い時), そのチェックしたり processCommand # lookupCommandでコマンド探してcallで実行する lookupCommand # 実行するコマンドを探しす call # コマンドを実行してる(redisClient c->cmd->proc()) # procはredisCommandTableで, コマンドごとに登録されていて、 # それが実行される. ↓こんな感じ struct redisCommand redisCommandTable[] = { {"get",getCommand,2,"r",0,NULL,1,1,1,0,0}, {"set",setCommand,3,"wm",0,noPreloadGetKeys,1,1,1,0,0},
例えばsetコマンドだと、procは
# src/t_string.c void setCommand(redisClient *c) { c->argv[2] = tryObjectEncoding(c->argv[2]); setGenericCommand(c,0,c->argv[1],c->argv[2],NULL,0); }
という感じで, valueをエンコードして, setGenericCommandに client, nx(謎), key, value, expire, unit(謎) を渡している.
流れはこんな感じ。
setCommand # 値をエンコードとか tryObjectEncoding # エンコードしようとしてる setGenericCommand # expireチェックとか setKey # 実際にキーに値をセット(この関数の中より下見てない, dbAdd or dbOverrideで書き込まれてるっぽい)
とにかくredisClientというやつが, コマンドの情報とか色々持っていて、そいつに対して値をセットしたり色々しながら 最終的にそいつが持ってる情報から実行するみたいな感じだった。とりあえずメモを残そうと思って残したけど、次読もうとするのいつになるか分からない。