旧gaaamiiのブログ

間違ったことを書いている時があります。コメントやTwitter、ブコメなどでご指摘ください

Ruby技術者認定試験(Gold)落ちた

前からRuby触ってるし大丈夫だろうと思ってて、前日にちょろっとやって受かる予定だった。結果は56点だった。馬鹿だった。

ポイント

リンク

試験前に読んだものや、試験終わった後にもやもやを解消するのに役立ったリンクなど。

kakakakakku.hatenablog.com

qiita.com

qiita.com

本はこの三冊がいいと思う。3冊ちゃんと読み倒せばGoldなんて簡単すぎるくらいかもしれない(自分はというと、Effective Rubyは読みかけ、メタプロRubyは読んでない。あと頭が悪い)。

公式問題集はいろいろひどかったから載せない。

もう1回くらい今月末に受けて受かりたい。1万5000円もかかるのが苦しい。とはいえ勉強やはり楽しい。しかし1万5000円...(以下無限ループ)

何で難しいのか・難しいものとどう向き合うか

難しさについて。

前提を知らない

前提を知らないと、難しいと感じる。=> 遠くにある高級そうなものではなくて、自分が理解できる近場の疑問を一つずつ解消していく。

訓練を必要とする

訓練を必要とするものは、素でいきなりやると難しく感じる。 => 訓練に時間を費やす決断をする。

必要がない

自分に必要がないものを理解するのはとても難しい => 必要が無いならやらない。必要だと感じたときにやる。

頭字語コマンドを展開するwdimというコマンドラインツールをgemとして公開しました

wdimという名前でgemを公開しました。ダブリューディムとかダブディムって読んでください。意味は What does it mean の略です。

シェルでwdim ls と打つとlist segmentsが返ってきます。つまり、頭字語やら略語やらジャーゴンになっていてひと目では理解しづらいUNIX/Linuxコマンドを展開してくれるコマンドラインツールになります。

使い方

インストール

gemコマンドが使える環境で以下を打ち込んでください。

$ gem install wdim
(権限がないとかいわれる場合は)
$ sudo gem install wdim

つかう

$ wdim cd
change directory

経緯

こちらに書きました。

shgam.hatenadiary.jp

今後

正直、まともに使えるようになる前にgemとしてリリースしてしまいました。ローカルでインストール作業(git cloneしてgem build してgem install)してくれる人は少ないと思うので、ちょろっと試す際に試しやすくするためだけに公開しています。

今後はディクショナリを充実させたり、シェル作業中にパッと目につくような装飾をつけたり、また、起動の速度が気になってきたりしたらrubyではなくCで書いてHomebrewで配付したりとかそういうことを考えています。

ディクショナリ(現状はlsのようなコマンドに対してlist segmentsのような意味が記述されているymlファイル)がなにより大事なのです。この頭字語コマンドの意味知ってるよ~という方からのプルリクお待ちしてます。頭字語の意味は検索すればたいてい出てくると思いますが、議論があるものもあり、微妙なものはIssuesで話しあえたりしたら楽しいなと思ってます。

UNIX/Linux初学者にやさしい世界をつくりましょう。

github.com

UNIXコマンド ls とか mv とかのソースコードの場所

自分でコマンドラインツール的な何かを作りたい時に参考にするために、ls とか mv とかのソースは手元に置いときたい。

Coreutils - GNU core utilities の Downloads というとこからダウンロードできます。ダウンロードしたものは以下のコマンドで解凍できます。

$ tar Jxvf coreutils-8.25.tar.xz

さて、早速 coreutils-8.25/src/mv.cとか読むぞーとおもむろにタグファイルを作って(ctags -R)中身を読もうとしたところ、オプションをパースする場所を見つけました。getopt_longか〜。中身が見たいぞ〜。と思ってタグジャンプしようとしたら、できないですね。これを見るには getoptというライブラリを見ないとだめですね。というわけで今度は The GNU C Library からglibc をダウンロードします。getopt.c が glibc-2.23/posix 下にありました。getopt_long という関数は同ディレクトリの getopt1.c にありました。めでたしめでたし。 coreutils-8.25/lib/getopt1.c にありました。めでたしめでたし。

「日本のWebエンジニアの大半が、変化に対応しきれなくなっている件について。」を読んだ感想

以下の記事がはてなブックマークで盛り上がっていました。TOEIC940点の人すごい。。。

d.hatena.ne.jp

中でも以下が一番ぐっと来ました。

UNIX/Linuxコマンドを英語で学習すると、pwd は「Print Working Directory」の略なので、そのまま英語の意味からコマンド名を覚えることができるなど、様々なメリットがありました。

名前はたいていそのツールが何を解決するのか、とかどんなアイデアなのか、とかを表しています。それを理解すると覚えやすいし、コマンドにどんなオプションが存在するのかも予想しやすい。だけど、UNIXコマンドのようにやたら頭字語になっていたりギークっぽい専門語となるとスルーしたくなります。僕はman コマンドを使う時しばらくそれを男性のことだと思っていたし(正解はman manでわかります)、Linux再帰的な頭字語(Linux is not unix)って聞いた時、なんだよそれって気持ちになりました。

変化激しいとこでやっていくのにはたくさん覚え続けなければいけないのはわかってるんですが、ツールの使い方を覚えて覚えて覚え続けるというのは人生を浪費しているような気もします。ツールの名前なりそれが作られた経緯やアイデアなどに着目して効率よくキャッチアップできるマンになりたいです。そういう時にコンピュータサイエンスなりはたまた別分野の教養なり知性なりなんやかんやが役立つと思うんだけど、結局どう考えても自分には無いものだらけなので今のところは「頑張る」以外になさそうだなと思いました。

もう今年24歳になるというのに「頑張る」しか言えることがなくてつらい...。以上です。

あわせて読みたい

karur4n.hatenablog.com

追記

github.com

UNIXコマンドで頭字語やわけわからん名前付けのものを取り出して意味を出力するCUIツールの試作をつくりだした。たぶん難しいことはないので、CUIツールの基礎とパッケージの公開の仕方を学んで、あとはひたすら辞書を充実させて、自分と同じように頭字語に悩む人にとって役立つものにしたい。

何が難しいのかを切り出すだけでも難しい

他人が書いたソフトウェアを動かして困ったことが起きると、問題の特定に7割くらいの時間を使う。経験があったり仕様が把握できていたりすれば時間は短くなると思う。簡単なスクリプトならまだしも、20本のスレッドが一つのプロセス内で互いにタイミングをはかってやりとりしているような複雑なソフトウェアを改修するとなると、何が難しいのかを切り出すだけでも難しい。ソースコードの行末コメントに /* bug */ とだけ付け加えられていて恐怖を煽ってくるものもある。それを書いた人はもうこの職場にいない。

問題の特定に(自分の頭の回転が遅いというのはあるけども)時間がかかると何が辛いのかというと、仕事をしてない感がすごい。仕事をしてない感がすごいと自己嫌悪に陥る。すると、冷静な判断を下したりとか長期的な視野を持つことができなくなっていく。良いソフトウェアは書けず、書こうとする気力も失っていく。

何か複雑なものと向き合うときに、何が難しいのかを切り出すだけでも難しいということを認識する努力も必要なのかもしれない。優秀なエンジニアでさえ Yak Shaving を避けられないのだから、停止しているような時間にいちいち後ろめたさを感じていたら、精神がもたない。

あわせて読みたい聴きたい

rebuild.fm

postd.cc

Ruby製のウェブサーバライブラリWebrickのソースコードを読む

そういや一年前、「ウェブサーバーのこと知りたい -> Rack読もう。」となって挫折した。少しずつ暖かくなって意識が高まってきたし、今やっている仕事がずいぶんと(すくなくともRailsアプリ書くのと比較すると)低レイヤーなところなので、良い感じの相乗効果を狙って今のうちにサーバーについて理解を深めておきたい。そういうわけで、今春はWebrick読もう。

読みかた

今度は挫折したくない。以下の手法に従って読む。

また、Cのソースにも触れることになると思うので以下も参考にする。

使うもの

動的解析

基本的に解析は動的解析から始めるのがよい。 静的解析とは、多かれ少なかれ、プログラムの動作を予想することである。 対して動的解析で見るのは事実である。 まず事実を見ておいたほうが方向付けがしやすいし、間違いも減る。 最適化する前にプロファイルを取れ、というのと似ているだろうか。 事件解決はまず現場から、というのでもよい。

とのこと。まずは動かす。

サーバー起動

 ruby -rwebrick -e 'WEBrick::HTTPServer.new(:DocumentRoot => "./", :Port => 8000).start'

なお、これは以下と同等(r オプション使うの初めてだ)。

ruby -e 'require "webrick";WEBrick::HTTPServer.new(:DocumentRoot => "./", :Port => 8000).start '
[2016-03-26 14:03:45] INFO  WEBrick 1.3.1
[2016-03-26 14:03:45] INFO  ruby 2.2.3 (2015-08-18) [x86_64-darwin14]
[2016-03-26 14:03:45] INFO  WEBrick::HTTPServer#start: pid=4563 port=8000

参考:ワンライナーWebサーバを集めてみた - Qiita

リクエストを投げる

クライアントとして、別のシェルを開いて以下を実行する。

https://i.gyazo.com/10287afed859f10d8aa06f1fa223d8c7.gif

curl localhost:8000

(クライアント側)

$ curl localhost:8000
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 3.2 Final//EN">
<HTML>
  <HEAD>
    <TITLE>Index of /</TITLE>
    <style type="text/css">
...(以下略)

(サーバー側)

localhost - - [26/Mar/2016:14:04:04 JST] "GET / HTTP/1.1" 200 4076
- -

クライアントからHTTPリクエストを投げたらちゃんとハイパーテキストを返してくれたので、ウェブサーバーとして機能したと言える。サーバー側のログには時刻やHTTPメソッド・プロトコルのバージョン・ステータスなどが出されている。

静的解析

前準備

さすがにGithubのウェブサイト上でファイルを一つ一つブラウジングして理解できる気がしないので、「ソースコード完全解説ガイド」に従っていくつかの前準備を行う。

ドキュメントを読む

今回は http://docs.ruby-lang.org の説明を参照する。

汎用HTTPサーバーフレームワークです。HTTPサーバが簡単に作れます。

WEBrickサーブレットによって機能します。サーブレットとは サーバの機能をオブジェクト化したものです。 ファイルを読み込んで返す・forkしてスクリプトを実行する・テンプレートを適用する など、「サーバが行なっている様々なこと」を抽象化しオブジェクトにしたものが サーブレットです。サーブレットWEBrick::HTTPServlet::AbstractServlet の サブクラスのインスタンスとして実装されます。

WEBrick はセッション管理の機能を提供しません。

ソースコード入手

WebrickRuby の標準ライブラリなので、Githubruby リポジトリから入手する。

git clone git@github.com:ruby/ruby.git

tags ファイルつくる

webrickはlib/下にある。そこでctagsコマンドを実行する。

cd ruby/lib/webrick
ctags -R

参考:ctagsと連携するように環境を構築する - Qiita

ファイル構成を見る

MacBook-Pro:webrick gaaamii$ tree .
.
├── accesslog.rb
├── cgi.rb
├── compat.rb
├── config.rb
├── cookie.rb
├── htmlutils.rb
├── httpauth
│   ├── authenticator.rb
│   ├── basicauth.rb
│   ├── digestauth.rb
│   ├── htdigest.rb
│   ├── htgroup.rb
│   ├── htpasswd.rb
│   └── userdb.rb
├── httpauth.rb
├── httpproxy.rb
├── httprequest.rb
├── httpresponse.rb
├── https.rb
├── httpserver.rb
├── httpservlet
│   ├── abstract.rb
│   ├── cgi_runner.rb
│   ├── cgihandler.rb
│   ├── erbhandler.rb
│   ├── filehandler.rb
│   └── prochandler.rb
├── httpservlet.rb
├── httpstatus.rb
├── httputils.rb
├── httpversion.rb
├── log.rb
├── server.rb
├── ssl.rb
├── tags
├── utils.rb
└── version.rb

読むの開始

先ほどのワンライナーをふたたび見る。

WEBrick::HTTPServer.new(:DocumentRoot => "./", :Port => 8000).start

まずは以下からざっくりと追う。

  • HTTPServer.new
  • HTTPServer#start

HTTPServer.new

インスタンス初期化時に何をしているのか。mountというメソッドでパスにサーブレットを割り当てているようだ。あとは @virtual_hosts という配列を初期化している。

HTTPServer#start

HTTPServerのインスタンスメソッドstart見ようとしても、ない。継承元のGenericServerのものだとわかる。

GenericServer#start

さて、このstartメソッドは何をしてるのか。コメントがあるので、それを見る。

137     ##
138     # Starts the server and runs the +block+ for each connection.  This method
139     # does not return until the server is stopped from a signal handler or
140     # another thread using #stop or #shutdown.
141     #
142     # If the block raises a subclass of StandardError the exception is logged
143     # and ignored.  If an IOError or Errno::EBADF exception is raised the
144     # exception is ignored.  If an Exception subclass is raised the exception
145     # is logged and re-raised which stops the server.
146     #
147     # To completely shut down a server call #shutdown from ensure:
148     #
149     #   server = WEBrick::GenericServer.new
150     #   # or WEBrick::HTTPServer.new
151     #
152     #   begin              
153     #     server.start     
154     #   ensure             
155     #     server.shutdown  
156     #   end   

意訳する。

「サーバーを起動してコネクション毎にブロックを実行する。このメソッドはシグナルハンドラあるいは他のスレッドの#stop#shutdownによってサーバーが停止するまでreturnしない。(以降、例外捕捉の説明)」

スレッド <--(コネクション)--> クライアント
スレッド <--(コネクション)--> クライアント
スレッド <--(コネクション)--> クライアント

という感じで、スレッドとコネクションとクライアントが1対1対1の関係になるのがこのstartメソッドを見るとわかる。

この処理はbegin節で囲まれてた中で無限ループしていて、先のコメントにあったようにシグナルハンドラなんかによって停止されたときにこの節を抜ける。するとensure節が実行されて、サーバーが停止する。

というわけで、実際のコードの中身について、大事そうなものをかいつまんで見てみていく。

  1. server_type.start
    1. setup_shutdown_pipe
    2. svrs = IO.select([sp, *@listeners], nil, nil, 2.0)
    3. sock = accept_client(svr)
    4. th = start_thread(sock, &block)
    5. thgroup.add(th)
server_type.start

server_type にはデフォルトではWEBrick::SimpleServerとなるので、このstartメソッドをみる。

(server.rb)
 27   class SimpleServer       
 28 
 29     ##
 30     # A SimpleServer only yields when you start it
 31 
 32     def SimpleServer.start 
 33       yield                
 34     end
 35   end            

yieldの一行しかない。渡したブロックそのまま実行するということがわかる。

setup_shutdown_pipe

よくわからない。パイプってなんだ(あとでみる)

svrs = IO.select([sp, *@listeners], nil, nil, 2.0)

IO.selectが何をしているのか。Rubyの組み込みライブラリなので、まずドキュメントにあたった方がよさそうだ。

http://docs.ruby-lang.org/ja/2.2.0/class/IO.html

IOクラスとは、

基本的な入出力機能のためのクラスです。

とのこと。では、このselectというメソッドはなにか。

http://docs.ruby-lang.org/ja/2.2.0/class/IO.html#S_SELECT

与えられた入力/出力/例外待ちの IO オブジェクトの中から準備ができたものを それぞれ配列にして、配列の配列として返します。 タイムアウトした時には nil を返します。

ソースも見てみる。IOクラスはwebrickの中には見つからないので、今回は pry-doc というgemを使ってpry(対話環境)から場所を見つけることにする。

[1] pry(main)> show-source IO.select
From: io.c (C Method):
Owner: #<Class:IO>
Visibility: public
Number of lines: 22

static VALUE
rb_f_select(int argc, VALUE *argv, VALUE obj)

Cのソースで、rb_f_selectという関数だということがわかった。

start_thread
ThreadGroup#add

ThreadGroup の定義元に飛びたいけど、これは組み込みライブラリ、つまりCのソースになるので、webrickの中にはいない。ということで、今回は pry-doc というgemを使ってpry(対話環境)上から場所を見つけることにする。

pry> show-source ThreadGroup#add

とすると、このメソッドの定義元がわかる。どうやらthread.c にある thgroup_addという関数らしい。

IO.select([sp, *@listeners], nil, nil, 2.0)

書き途中です。

Webサーバについてのメモ

一から調べだした。

雑理解

まず、調べる前に自分の雑理解を書き出す。

  • WebサーバはクライアントからHTTPリクエストをもらってHTTPレスポンスを返す(HTTPサーバだ)。
  • データのやり取りの際には recv とか write みたいなUnixシステムコールで送受信を実現することになる。
  • たくさんのクライアントから同時にリクエスト来ても処理できるようにスレッドやプロセスを分けるやり方もあるけど他の方法もある(らしい)。
  • TCP 接続に必要な情報はIPアドレスとポート(だけ?ほんとに?)。

OSSを読む

参考

コンピュータへの畏敬みたいな感情

@moutend さんがこんなエントリを書いてバズっていた。

http://qiita.com/moutend/items/2696139d0b96805ea415qiita.com

何がすごいってもちろん @moutend さんがすごいだけの話でもあるんだけど、やっぱりこういうの読むとコンピュータが人間の能力拡張してるよすごいなー、と感動する。そういえば以前「ハクティビズムとは何か」とか「2045年問題」とか、あとは小飼弾さんの「コードなエッセイ」とかでそういう話を読んで、ろくにプログラミングもできないくせにコンピュータすごいと確信したのを思い出した。仕事としてコンピュータを触っていてうまくいかないことが多いと忘れがちだけど、身体能力を拡張して何かできるという全能感みたいなものを少しでも感じられるようにコンピュータを使っていきたい。そのためにはコンピュータへの畏敬みたいな感情を時々思い出していけたらいいと思う。あともう一度言うけど、@moutend さんはすごい。

「Ruby under a microscope」 読んでる

ソースコードが何がどうなって実行されるのかを知りたい。

トークナイズ

Rubyスクリプトを実行する時、そのソースコードはまずトークンっていう形にばらばらにされる。本書では、Ripperという標準ライブラリを使ってこの動きをみてる。

パース

トークンにしたら、パースします。パースするんだけど、これにはグラマーとパースジェネレータというのを使うことになる。

書き途中です

こちらに少しずつポストしていく。