「HACKING」や「Linuxカーネル2.6解読室」など、最近の「買って良かった技術書」について

技術書の積読は悪いことでは無いと言いたい」という前回のブログにも書きましたが、自分は適当に技術書を買う事が多いです。

south37.hatenablog.com

その中でも、最近自分の中で「当たり」だったものについて簡単に紹介してみたいと思います。

HACKING

まず、期待値の割にすごく良かったのが、「HACKING」という本です。この本では、様々なパターンの脆弱性が豊富なコード例とともに解説されています。僕は、六本木ではたらくソフトウェアエンジニアへのよくある質問とその答え (FAQ) というページでこの本の存在を知りました。

気になっていたもののそれほど期待していなかったのですが、詳細な説明とともに実践的な(?)脆弱性攻撃の手法などが載っており、内容がものすごく充実していました。例えば、バッファオーバーフローについて、自分は最初は「バッファオーバーフローぐらい知ってるぞ」などと調子づいていたのですが、それを実現するための鮮やかな手際、環境変数を利用したスマートな攻撃方法、はたまたシェルコードの説明やシェルコードを自作する方法まで載っていて、自分の知らなかった情報が詰まっていてすごく面白かったです。「root権限で動くprocessに脆弱性があるとすごく危険」という事実も、知識としては知っていたものの、実際に「脆弱性を突いてrootでshellを立ち上げるコード」を目にすることで「実感」を持つことが出来るようになりました。

Linuxカーネル2.6解読室

また、別の本で買って良かったなーと思ってるのは、「Linuxカーネル2.6解読室」という本です。これは「明倫館」という神保町の古本屋で買ったもので、完全に「ちょっと気になったから適当に買ってみた」ものでした。古本だから新品で買うより安くて、お得に感じたのも買った理由の1つです。

実は、自分はLinuxBSDカーネル本を他にもいくつか持ってるのですが、それらはあまりモチベーションを保って読み進められませんでした。だから、正直「Linuxカーネル2.6解読室」も積読されちゃうかもなーと思ってあまり期待してませんでした。

ところが、この本はすごく読みやすくて、モチベーションが尽きることがありませんでした。いまもチビチビと読み進めています(まだ全体は読めてなくて、PART 1 のカーネルプリミティブ、つまり第6章までと、後はPART 2のプロセス管理やPART 3のメモリ管理周りをつまみ食いしてる感じです。)

この本が自分にとって良いと感じたのは、「コードと説明のバランスが良いから」かもしれません。

カーネルの説明というと、場合によっては「図による概念の解説」や「パラメータや定数の網羅的な説明」に終始しがちで、イマイチ何が起きてるかイメージしづらかったり、単なる暗記作業になってしまったりします(リファレンス的な本ならそれで良いと思いますが)。

ところがこの本では、Linuxカーネルがどういう戦略でどういった機能を実現してるか、またその動作が実際のコードとともに解説されていて、覚えやすいしイメージしやすくなっていました。また、コード自体もすごく参考になるものでした。

自分がLinuxカーネルについて勉強したいと思っていた理由は、「自分が普段利用している、依存しているものが実際に何をしているか知っておきたい」と思っていたからと、もう1つは自分の尊敬するHajime MoritaさんRebuild.fm ep.127で「最適化手法については、OSの最適化戦略などを知っておくとすごく勉強になる」と言っているのを聞いたからでした。

Linuxカーネル2.6解読室は、そういった自分の目的を叶えてくれる本でした。その意味でも、「適当に買って」本当に良かったと思っています。

最近の「買って良かったシリーズ」まとめ

という訳で、最近の自分のマイブームはHACKINGLinuxカーネル2.6解読室でした。多分、今後も適当に買いながら、たまに面白い本に出会うんだろうなーと思ってます。

Hacking: 美しき策謀 第2版 ―脆弱性攻撃の理論と実際

Hacking: 美しき策謀 第2版 ―脆弱性攻撃の理論と実際

Linuxカーネル2.6解読室

Linuxカーネル2.6解読室

技術書の積読は悪いことでは無いと言いたい

いきなり自分語りをしたいと思います。 自分は結構ソフトウェア関連の技術書を読むのが好きで、よく本屋で適当に買っては読んだりしています。週に1~2冊くらいは買うので読みきれないものはどんどん積読しています。Kindle の中に眠ってる本、机の上や棚に積み上げられた本、様々な本が日に日に増えて行くなーと感じています。

この積読の是非について考えてみたいと思います。

問: 積読は避けるべきこと、悪いことか?

積読は避けるべきこと、悪いことか?」という問について。

この問に対しては、いくつかの考え方、答えがあると思います。

例えば、1つの意見として、「本を買うのはお金がかかるから、積読して読まないのは勿体無い。避けるべきことだ」という考え方もあります。あるいは別の意見として、「買わなかったせいで2度と読めなくなる本もある。読む可能性を作るためなら、積読される可能性があろうとも買うべきだ」という考え方もあります。それぞれ、意見は違えど言い分はもっともです。

では、僕自身はどうなのかと言えば、僕は完全に「積読肯定派」です。理由は、自身の経験として「積読しておいて良かった」ことが多々あったからです。

僕が積読肯定派である理由

僕がどういった経験をして積読肯定派になったのか?一例を紹介したいと思います。

僕は技術書を買った時、読まずにそのまま机に置く、あるいは「はじめに」だけ適当に呼んでそのまま放置する事が多々あります。一方、読み始めたらものすごく面白くて止まらなくなって、休日を潰して一気に読んでしまう事もあります(そういった場合、土日で終わらなかったら平日の通勤時間や帰宅後の時間を使って読み進めます)。

この 「適当に買ってみたけどすごく良かったパターン」が、1つの大きな成功事例として僕の中で強く印象づいています。だからこそ、例え積読になろうとも技術書を買った方が良いと僕は思います。

では、僕が積読を肯定する理由がそれだけかというと違っていて、もう1つ別の理由もあります。それは、「昔買ってあまり読んでなかったけど、読んでみたらすごく面白い技術書だった」という経験があるからです。

僕は技術書を色々なところに積み上げていて、手持ち無沙汰になると適当に手にとってパラ見をします。そうした時、まれに「自分はこんな面白い技術書を持っていたのか」と感動する事があります。

それは、例えば「中盤の章に自分がまだ読んでない面白いトピックがあった」ケースであったり、あるいは「自分の知識がついた事によって面白さが理解できるようになった」ケースであったりします。状況は様々ですが、手元にある事によって偶然面白さに気づけることがあります。これが僕が積読を肯定する2つ目の理由です。

まとめ

自分の考えをまとめてみます。

僕は「積読肯定派」、つまり「積読になる可能性があろうとも、ガンガン技術書を買った方が良いと思う派」です。それは、「買ってから面白さに気づく本もあるから」であり、はたまた「積んで置く事で後から面白さに気づける場合もあるから」です。

自身の考えをまとめておこうと思い、ブログに書いてみました。

ブログテーマを変えてみました

2016年にもなって心機一転という事で、ブログテーマを更新してみました。

参考にしたのは Svbtle というブログサービスのデザインです。 Swift のテストフレームワーク Quick で有名な modocache さんが Svbtle を使って記事を書いていて、あまりにカッコよかったのでついつい真似してしまいました。ほぼパクりみたいになっちゃったのは反省してます。

Medium だったり Svbtle だったり、最近は顔出しが流行ってるみたいなのでそこも真似してみました。若干の恥ずかしさはありますが、気にしない事にします。

2016年の抱負

2016年の抱負を書きたいと思います。去年は Wantedly に新卒として入社して、目の前の仕事を必死でこなしていたらあっという間に1年が過ぎました。若干の焦りを覚えていて、特にアウトプットがすごく少なかったのが反省点だと思っています(このブログも1回しか更新しませんでした)。

2016年はブログや発表といった形でアウトプットを増やしていけたらと思ってます。

最近のマイブーム

最近は、値段が高くて学生時代には手が出せなかった「古典的名著」を買うのがマイブームになってます。TAPL や ドラゴンブック、赤い悪魔本など、買って満足してどんどん積み上がっていってます。積み上げるだけだと勿体無いので、少しずつでも読んでいこうと思います。

YAPC::Asia 2015に行ってきた!!

8/21, 22の2日間 YAPC::Asia に行ってきた。

YAPC::Asia の存在は前から知っていて、でも Perl よくわからないしお金無いし。。とか言って去年は行かなかったんだけど、今年は働き始めてチケット代くらいは出せるようになったので勢いのままに Early Bird Ticket を買って行ってきた。

丸2日行ったけど、振り返ってみたらなんだかあっという間だった。

自分が聞いたトーク一覧

面白かったトーク

TBD by Matz

このトークについては toggetter を見ると雰囲気伝わると思うけど、とにかく Matz さんの話の面白さとトークの完成度の高さが最高だった。 http://togetter.com/li/863417

Ruby作者だからRubyをdisれる」とか「Rubyの良くないところはPerlの影響を受けたこと」とか問題発言もぶち込みつつ、言語デザイナーとしての考えとかが聞けたのが良かった。

Matz さんは将来的に「ほとんどコードを書く必要が無い未来」が来ると考えてて(1ファイルくらいのスクリプトで考えた事が実現できる未来、おそらく高度に抽象化された基盤の上に乗ってる)、昔は自分もそういった未来が来ると無邪気に考えてたけど今はそう思えなくなってるのを実感した。

自分は基盤となるライブラリやフレームワークが全てをカバーするのは無理なんじゃ無いかと思ってる。例えば Ruby on Rails みたいなフレームワークを使うとちょっとした DSL を書くだけで Web アプリケーションに必要な機能が作れるけど、Railを外れると自分でガリゴリ実装を書く必要がある。Rails ほどの規模であっても全てはカバー出来ない事を考えると、短いコードだけで 全て を実現出来る日は来ないんじゃ無いかと思う( 全て じゃなくて よくあるユースケース を抑えるだけなら出来ると思うし、実際そういった流れはあると思うけど)

とりあえず雑にまとめると、言語デザイナーとしての生き方が楽しそうだった。

実践nginxモジュール開発〜CとLua

cubicdaiya さんのトーク。mosaic の nginx 回を聞いてどんな人か気になってたので、話が聞けて良かった。

ngx_small_light の採用事例として弊社(Wantedly)の nginx-image-server が取り上げられてたのはちょっと嬉しかった。 https://github.com/wantedly/nginx-image-server

トークの前半は nginx のモジュールの作り方の説明で、用意しなきゃいけない struct とかが決まっててお作法は覚えなきゃいけないけど、簡単な処理をするモジュールくらいなら作れそうに感じた。

後半は ngx_lua はパワフルで良いよーってお話しで、提供されてる API に詳しくなれた。ngx_lua は昔一瞬だけ使ったことがあって、その時は外部プロセスを一瞬起動するみたいな簡単な処理をしただけだったけど、それでもすごく使いやすかったのが印象的だった。Webサーバにスクリプティング環境があるのは、夢があると思う。

【特別企画】YAPCあるある(仮)

まさにオールスター企画。
miyagawa さん、takesako さん、maki さん、941 さんみたいなこれまでに YPAC を運営してきた人たちによる YAPC の振り返りトークで、安定して面白かった。

toggeter 見ると盛り上がりがわかりそう http://togetter.com/li/863907

HTTP2 時代の Web

Jxck さんの HTTP2 についてのトーク。ちょうど最近 「ハイパフォーマンスブラウザネットワーキング」を読んでたので自分の中ではタイムリーな話しだった(今年の初めに RFC化されたから世間的にも注目浴びてるけど)。

multiplex で速くなるっていうのは知識としては知ってたけど、画像を使ったデモがすごく分かりやすい & 印象的で良かった。 速い って一口で言ってもいろんな速さがあって、例えば html 降ってくるのが速くなってもフロントで詰まる事は全然あって、大きな画像がページの上部に6枚あればそれで簡単にコネクションが占有されてしまうというのが印象的だった。

HTTP/2 を導入すべきかどうかみたいな話しもあるけど、 rebuild で oku さんも話してたみたいに apache や nginx みたいな Web サーバーがどうせ実装する(&ブラウザは既に実装してる)から、素直にみんな使うようになるんじゃないかと思う。

全体の所感

著名な人が集まってて、オールスター感がすごかった。 特に、 rebuild や mosaic みたいなPodcastを最近は聴きまくってたので、そこに出てた人が喋ってるのを見れたのが嬉しかった。(Jxck さんとか声のイメージしか無かったので、こんな人だったのかーみたいな)

残念だったのは、5トラックあるから休まず出てもトーク全体の 20 % しか聞けない事。これはまあ構造上仕方が無い事ではあるんだけど、面白そうなトークが被りまくってて他の直接聞けないのは悲しいと思った。 直接トーク聞いて感じたのはスライドだけでは伝わらないものがけっこうあるって事で(例えばスライドに載せてないけど話してた重要な事とか会場での盛り上がりとか)、よく発表したスライドが公開されてるけどトークの動画も公開して欲しいと感じた。

全体として、YAPCが開催されて、こうやってYAPCに行けて良かったと思う。 スタッフ、スピーカー、参加者のみなさん、お疲れさま & ありがとうございました。

webmockすごい

エラー出ても使い方を教えてくれて優しい

$ ruby webmock.rb
/Users/(ユーザー名)/.rbenv/versions/2.1.5/lib/ruby/gems/2.1.0/gems/webmock-1.20.4/lib/webmock/http_lib_adapters/net_http.rb:114:in `request': Real HTTP connections are disabled. Unregistered request: GET http://www.example.com/ with headers {'Accept'=>'*/*', 'Accept-Encoding'=>'gzip;q=1.0,deflate;q=0.6,identity;q=0.3', 'User-Agent'=>'Ruby'} (WebMock::NetConnectNotAllowedError)

You can stub this request with the following snippet:

stub_request(:get, "http://www.example.com/").
  with(:headers => {'Accept'=>'*/*', 'Accept-Encoding'=>'gzip;q=1.0,deflate;q=0.6,identity;q=0.3', 'User-Agent'=>'Ruby'}).
  to_return(:status => 200, :body => "", :headers => {})

registered request stubs:

stub_request(:any, "http://www.example.com/").
  with(:body => "abc",
       :headers => {'Content-Length'=>'3'})

============================================================
  from /Users/(ユーザー名)/.rbenv/versions/2.1.5/lib/ruby/2.1.0/net/http.rb:1280:in `request_get'
   from /Users/(ユーザー名)/.rbenv/versions/2.1.5/lib/ruby/2.1.0/net/http.rb:474:in `block in get_response'
  from /Users/(ユーザー名)/.rbenv/versions/2.1.5/lib/ruby/gems/2.1.0/gems/webmock-1.20.4/lib/webmock/http_lib_adapters/net_http.rb:123:in `start_without_connect'
    from /Users/(ユーザー名)/.rbenv/versions/2.1.5/lib/ruby/gems/2.1.0/gems/webmock-1.20.4/lib/webmock/http_lib_adapters/net_http.rb:150:in `start'
  from /Users/(ユーザー名)/.rbenv/versions/2.1.5/lib/ruby/2.1.0/net/http.rb:473:in `get_response'
   from /Users/(ユーザー名)/.rbenv/versions/2.1.5/lib/ruby/2.1.0/net/http.rb:455:in `get'
  from webmock.rb:7:in `<main>'

Pryではトップレベルで定義したメソッドがObjectクラスのpublicなインスタンスメソッドになる

表題の通り。

今日Pry触ってて気づいたんだけど、Pryのトップレベルで定義したメソッドはObjectクラスのpublicなインスタンスメソッドになるっぽくて、大抵のオブジェクトから呼び出せる様になる。意図した仕様なのかバグなのかは分からないけど、びっくりしたからメモっとく。

ちなみにRubyのversionは2.1.5。Pryは普通にgem installした。irbRubyを普通に起動した場合には挙動が違ってて、privateなインスタンスメソッドになる。

$ ruby -v
ruby 2.1.5p273 (2014-11-13 revision 48405) [x86_64-darwin14.0]
$ pry -v
Pry version 0.10.1 on Ruby 2.1.5

何に驚いたのか?

以下にコードで例を示す。

[1] pry(main)> def my_method
[1] pry(main)*   p 'my_method'
[1] pry(main)* end
=> :my_method
[2] pry(main)> [].my_method // arrayオブジェクトのメソッドとしてmy_methodが呼び出せる!!
"my_method"
=> "my_method"
[3] pry(main)> [].methods.include?(:my_method) // arrayオブジェクトの呼び出し可能なメソッドにmy_methodが含まれてる!!
=> true

トップレベルで定義したmy_methodメソッドが、空のarrayオブジェクトである[]から呼び出せている。割と驚きの挙動。

なぜこうなるのか?

表題にも書いたけど、Objectクラスのインスタンスメソッドとしてmy_methodが定義されてるのが原因。Objectクラスはほとんどのオブジェクトの上位クラスに位置しているので、大抵のオブジェクトからmy_methodが呼び出せるようになる。

[4] pry(main)> Object.instance_methods(false).include?(:my_method) // instance_methods(false)で、そのクラスで定義されたinstance_methodsが取得できる
=> true
[5] pry(main)> [].class
=> Array
[6] pry(main)> [].class.superclass // Arrayの上位クラスにObjectが位置している
=> Object

自分で適当に定義したクラスもObjectクラスを継承した状態になるので、そこから生成したオブジェクトもmy_methodを呼び出せる。

[7] pry(main)> class MyClass; end
=> nil
[8] pry(main)> my_obj = MyClass.new
=> #<MyClass:0x007fbf6972ce20>
[9] pry(main)> my_obj.my_method
"my_method"
=> "my_method"

Objectよりもさらに上位のBaicObjectを継承すれば、こうはならない。

[10] pry(main)> class MyBasicClass < BasicObject; end
=> nil
[11] pry(main)> my_basic_obj = MyBasicClass.new
=> #<MyBasicClass:0x3fdfb62dab38>
[12] pry(main)> my_basic_obj.my_method
NoMethodError: undefined method `my_method' for #<MyBasicClass:0x007fbf6c5b5670>
from (pry):12:in `__pry__'

ここまでがPryでの話。

irbRubyコマンドで起動した場合はどうなるか

Objectのprivateなインスタンスメソッドとして定義されるので、外部から呼び出しは出来ない。

irb(main):001:0> def my_method
irb(main):002:1>   p 'my_method'
irb(main):003:1> end
=> :my_method
irb(main):004:0> [].my_method
NoMethodError: private method `my_method' called for []:Array
  from (irb):4
  from /Users/(ユーザ名)//.rbenv/versions/2.1.5/bin/irb:11:in `<main>'

じゃあ何でこんな挙動(わざわざObjectクラスにprivateなインスタンスメソッドとして定義)になってるかと言うと、オブジェクトのメソッドを定義する時なんかにトップレベルで定義されたメソッドを使えるようにする為。

irb(main):005:0> class MyClass
irb(main):006:1>   def try_2_my_method
irb(main):007:2>     my_method           // my_methodが使える!!
irb(main):008:2>     my_method           // my_methodが使える!!
irb(main):009:2>   end
irb(main):010:1> end
=> :try_2_my_method
irb(main):011:0> my_obj = MyClass.new
=> #<MyClass:0x007fefdb285938>
irb(main):012:0> my_obj.try_2_my_method
"my_method"
"my_method"
=> "my_method"

要は、Rubyではいわゆるグローバルスコープ的な機能を提供する為にObjectクラスを利用してるっぽい。

この事は、BaiscObjectを継承するクラスの中でインスタンスメソッドを定義する時にはトップレベルで定義したメソッドが使えない事からも確認できる。

irb(main):013:0> class MyBasicClass < BasicObject
irb(main):014:1>   def try_3_my_method
irb(main):015:2>     my_method
irb(main):016:2>     my_method
irb(main):017:2>     my_method
irb(main):018:2>   end
irb(main):019:1> end
=> :try_3_my_method
irb(main):020:0> my_basic_obj = MyBasicClass.new
(Object doesn't support #inspect)
=>
irb(main):021:0> my_basic_obj.try_3_my_method
NameError: undefined local variable or method `my_method' for #<MyBasicClass:0x007fefdc86dc50>
    from (irb):15:in `try_3_my_method'
  from (irb):21
  from /Users/(ユーザ名)/.rbenv/versions/2.1.5/bin/irb:11:in `<main>'

try_3_my_methodメソッドの定義の中でmy_methodを呼び出そうとしてエラーが出てる事が分かる。my_methodはグローバルに定義されてる訳では無くて、あくまでObjectクラスのインスタンスメソッドとして定義されてる事が確認出来たと言える。

まとめ

Pryの驚きの挙動から始めて、Rubyメソッドスコープの仕組みについての知見を得た。あとどうでも良いかもだけど、methodsとかinstance_methodsとかprivate_instance_methodsとかsingleton_methodsみたいな定義されたメソッドをarrayで取得する系のメソッドが今回かなり役立ったので、使っていくと良いと思う。特に、falseを引数として渡すと上位クラス由来のものは取り除いてくれるので、どこでメソッドが定義されてるかが特定しやすかった。