Yoichi's diary


2014-12-01

_ 菅原文太さん死去

わたしのグランパ」って筒井康隆原作だったのか。知らなんだ。


2014-12-02

_ [windows] heapstat 3.0.0.0

off-by-oneエラーを修正し、umdhと結果比較の上リリースした。

テスト自動化したい。


2014-12-03

_ [python] code golf

checkio の Prime Palindrome Golf、やりだしたら面白くてはまってしまった。いろいろやってるうちに、文字列とブール値の掛け算ができるとかいうムダ知識が得られたり。

2014-12-04

_ リーダブルコード 社内勉強会その1

  • std::list が O(1) と既定されたのは C++11 から (参考)
  • 最初スコープが狭いので短い名前を使っていたが、徐々に広がっていった場合どうする?→どこかでリファクタリングする
  • 変数名に単位をつけたとき、ログのメッセージを更新し直し忘れることがありがち
  • 変数宣言は型名と変数名の対応表。短かい変数名にしてるとき、使われる箇所の視界に入っていれば助かる
  • 一時的であることを表明したい場合にはtmpという変数名はあり
  • ここに参加してない人への展開は?→コードレビューの際に指摘する。指摘の根拠をちゃんと説明して伝える。
書いてあったことの紹介の後、持ち寄った社内の製品コードについて、ここはどうしたらいい?という議論をした。

2014-12-05

_ [python] From List Comprehensions to Generator Expressions

読んだ。先日触れたコードゴルフで2文字減らせた。


2014-12-06

_ 関西関数型道場(に行けず)

奥さんに風邪をうつしてしまい辛いとのことで、置いて行くこともできずキャンセル。家に風邪を持ち込んだのは自分なので仕方ない。

_ [python] functional style with generator

generatorを使うとどうありがたいのかを感じるため、例を考えてみた。
問題
(1) 1から100までの間に含まれる素数のリストを求めよ
(2) 100から200までの間に含まれる素数のリストを求めよ
(3) 100からの整数に含まれる素数の先頭から100個のリストを求めよ
まず普通のやり方で(1)から解いてみる。素数を判定する関数を作って、1 からの整数を順に判定して、真になったものをリストに入れていく。
def is_prime(n):
    if n < 2:
        return False
    for i in range(2, n-1):
        if n % i == 0:
            return False
    return True
#
def prime_in_100():
    lst = []
    for i in range(1, 100):
        if is_prime(i):
            lst.append(i)
    return lst
#
if __name__ == '__main__':
    print(prime_in_100()) # [2, 3, ..., 97]
次に(2)を解くために prime_in_100() を拡張してやると、
def prime_in_range(begin, end):
    lst = []
    for i in range(begin, end):
        if is_prime(i):
            lst.append(i)
    return lst
#
def prime_in_100():
    return prime_in_range(0, 100)
#
if __name__ == '__main__':
    print(prime_in_100()) # [2, 3, ..., 97]
    print(prime_in_range(100, 200)) # [101, 103, ..., 199]
のように解くことができる。さて、(3) を解くためには prime_in_range() はそのままでは 使えない(end をイテレートして無理やりつかうというのはできなくはないがとても効率が悪い)ので、 beginから100個になるまで積み上げる関数を新たに作って解いてやると、最終的に以下のようになった:
def is_prime(n):
    if n < 2:
        return False
    for i in range(2, n-1):
        if n % i == 0:
            return False
    return True
#
def prime_in_range(begin, end):
    lst = []
    for i in range(begin, end):
        if is_prime(i):
            lst.append(i)
    return lst
#
def prime_in_count(begin, count):
    lst = []
    i = begin
    while count > 0:
        if is_prime(i):
            lst.append(i)
            count -= 1
        i += 1
    return lst
#
def prime_in_100():
    return prime_in_range(0, 100)
#
if __name__ == '__main__':
    print(prime_in_100()) # [2, 3, ..., 97]
    print(prime_in_range(100, 200)) # [101, ..., 199]
    print(prime_in_count(100, 100)) # [101, ..., 691]
    print(len(prime_in_count(100, 100))) # 100
うーん。prime_in_range,prime_in_countで同じようなコードが重複しているのだけど、 一つにまとめるのは難しそうだし、それぞれが何をやっている実装なのかぱっと見でわかりにくい。 ここでおもむろに
def gen_prime(n):
    while True:
        if is_prime(n):
            yield n
        n += 1
という関数を導入してやると、先ほどのコードは以下のように書き直せる。
from itertools import takewhile,islice
#
def is_prime(n):
    if n < 2:
        return False
    for i in range(2, n-1):
        if n % i == 0:
            return False
    return True
#
def gen_prime(n):
    while True:
        if is_prime(n):
            yield n
        n += 1
#
def prime_in_range(begin, end):
    return list(takewhile(lambda x: x < end, gen_prime(begin)))
#
def prime_in_count(begin, count):
    return list(islice(gen_prime(begin), count))
#
def prime_in_100():
    return prime_in_range(0, 100)
#
if __name__ == '__main__':
    print(prime_in_100()) # [2, 3, ..., 97]
    print(prime_in_range(100, 200)) # [101, ..., 199]
    print(prime_in_count(100, 100)) # [101, ..., 691]
    print(len(prime_in_count(100, 100))) # 100
だいぶすっきりした。本質的に難しめのところ(素数の判定とか、素数を順に探すgeneratorの定義)のコード量は多いけど、それを使ってリストを作っている部分のコード量が少なくなっていて、何してるかもぱっとわかる。これで似たような問題が追加されても怖くない。

2014-12-07

_ [git] 非コーダ向けのgit

先日同僚と話をしていて、他所の部署ではいまだに構成管理してなかったりするらしいという話を聞いて驚いた。機会があれば試しに使ってみてもらえるとよいなと思ったので、いくつか良さそうな紹介を探してみた。

2014-12-08

_ 同じファイルを複数ウィンドウで表示

「リーダブルコード」の4.2の、関数呼び出しの書式を揃えてコメントを一つにまとめるという話を読み返していて、「こう書いてて呼び出しが多くなってきて1ページに収まらなくなったら、コメントのところを表示しながら実装箇所を見れないといかんよな」と思ったので、同じファイル内の複数の箇所を同時に参照したいときの、いろいろなエディタでのやり方を調べてみた。 Emacs, vim は知っていたが、Visual Studio でそんなに簡単にできるとは知らなかった。

2014-12-09

_ 名著『リーダブルコード ―より良いコードを書くためのシンプルで実践的なテクニック 』を解説者と一緒に読み解こう

Schooの授業を受けてみた。コードを読む人の気持ちになって考えて書くというのは、意識はしているつもりでいるものの、なかなかうまくできている気がしなくて日々悩んでいる。授業の中では、「ドキュメントを書いてみる」、「書いたライブラリを使う側のコードを書いてみる」のがよいのではというアドバイスをされていた。

最近やっている仕事では、自分たちで過去に書いたライブラリと、過去には中身まで見ていなかったがそれを使うアプリがあり、アプリとライブラリの両方を拡張していく作業をしていて、その中でアプリ側の実装を読んでいくと、ところどころ無理を強いちゃっているなという箇所が出てきている。使う側の視点が不足してたんだなと反省しつつ、せめて拡張部分は無理のないようにと、ある時はアプリ側の開発者の帽子、ある時はライブラリ側の開発者の帽子と、2つの帽子を交互にかぶりながら対応していこうとしてる。

あと、コードを読む時にいいところを探そうというのは、意識して行こうと思う。


2014-12-10

_ [python] checkio: DNA Common Sequence

例が間違っているなと思いつつ、無理やりそれに合わせたもので Run&Check したらこけた(その後例も修正されているのを確認した。更新のタイムラグがあるのかな)。

気を取り直して挑戦しているが、シーケンスが長い場合に計算が終わらないので再考中。


2014-12-11

_ リーダブルコード 社内勉強会その2

今回の範囲:4章 美しさ、5章 コメントすべきことを知る、6章 コメントは正確で完結に

読む人が「えっ」と思う所にコメントを書くべきだけど、コード書いている自分でなかなか気づけない。どうしたらよいか?という疑問に対しては、レビューされるという意識を持って書くと、質問されそう、突っ込まれそうなところを自然と想像するのでいいという話があった。確かに気を引き締めて自身でコードを見ると、その後レビューするレビューア(別の人)よりも厳しい目で見れる部分があるなと思った。

あと今回の例題では、先日の須藤さんの講義で聞いたことを受け、手本になるようないいコードをなるべく集めるようにしてみたところ、前向きな話ができてよかったと感じた。


2014-12-13

_ [scala] 関西Scala勉強会

ScalaわかってないしJavaの前提知識もないしでアウェイ要素が多い状態で参加したが、DBの話(Slickでfilterとかmapとか、リスト操作みたいな感じでSQLできる)と、Play2のCacheを置き換える話が興味深かった。

あと、アンカンファレンスにて、怪しい所は名前つけるとか変数に入れるとかしてデバッガで扱えるようにしたりする。バッドノウハウ的だが。。。というお話を聞けたのはよかった。何か銀の弾があるわけではないということで安心(?)した。

_ [python] checkio: DNA Common Sequence

泥臭く最適化をかけていって何とか我慢できるくらいの時間で計算できるようになった。泥まみれのコードはかなり汚い。

先に解いた他の人の解答を見て試してみたら、見た目すっきりしているし何百倍も速くてすごい。どういう処理になってるのか理解が追いつかなくてくやしい。


2014-12-16

_ [python] golf

ループで閾値を突き抜けても構わない(そこまでで絶対breakすると保証できている)なら、閾値の式を十分大きな数値リテラルに入れ替えることでコード減らせる場合があった。


2014-12-17

_ 寒すぎる

通勤するとき水たまりが凍っていた。

_ C++のif文のスコープ

リーダブルコードで出てきていたが、使ったことなかったのでためしてみた。変数は else の方からも参照できる。 https://gist.github.com/yoichi/3e891274b6c1e23b9f00

どういうときに使うと有効なんだろう?


2014-12-18

_ リーダブルコード 社内勉強会その3

今回の範囲:7章 制御フローを読みやすくする、8章 巨大な式を分割する、9章 変数と読みやすさ

  • 不等号の順序は、左に小さいものがあった方がイメージしやすいという意見もあり。
  • 範囲を表す 1 <= x && x <= 10 のような場合は例外的に可。python なら一つの式に書ける。
  • 早めに返すときはリソース解放漏れに注意が必要。デストラクタが勝手に呼ばれるとか、usingとかできるならそういうこと気にしなくていい。
  • 早めに返すの利点は最後に残ったメインの部分を読むときに、先に返した状況たちを気にせず集中できること。
  • if (SUCCEEDED(hr))でつなげる書き方もある。gotoだと途中に宣言を書けないが、これなら書ける。Code Completeではこの書き方が紹介されているらしい。
  • Error Handling in COM にエラー処理のいろいろなパターンのAdvantage/Disadvantageがまとまっている
  • if のスコープ。変数の初期化しかできないので、複雑な条件を書きたい場合はifの外で宣言する必要がある
  • C++ の規格書は買わないと読めないが、ドラフトは無料で読める。

2014-12-19

_ [DevKan] Dockerを現場に取り入れてみよう!

BSD jailみたいなものだという大雑把なイメージしか持ってない、つかった事ないという状態で参加。

層ごとの差分の管理ができる、層を重ねるのは127枚までという話から、何となくunionfs的なものを使っているのかと思って、後で調べたら aufs というunionfsの置き換えが使われていて、それの制限のようだった。

dockerコマンドをつかってお手軽に管理できるというのがポイントと感じた。

_ 忘年会

一次会終わりかけだったので吉牛でごはん食べてから二次会に合流。


2014-12-20

_ try docker

先日の勉強会で、試してみるとすぐイメージつかめるよと言われたので、以下を参考にコンテナ起動するところまで試してみた。

vagrantも初体験でしたが、ドキュメントの通りにやったら簡単にCoreOSが立ち上がり、あとはCoreOS上でdockerを叩いてコンテナ起動まですんなり行けました。

次は dotinstallにDocker入門のレッスンがあるようなので見てみようかな。


2014-12-21

_ 古本処分

ブックオフに古本出しに行って、待てども待てども呼ばれないので聞いたら、出したものが見当たらないので探しますとのことで、一旦帰宅して連絡を待ったところ、他の人のものと混ざって処理されてしまったらしかった。そんなこともあるのね。

_ 脱皮

飼っているザリガニが久しぶりに脱皮していた。


2014-12-24

_ ブーケ

帰って袋から出したら水がたれて奥さんに叱られた。


2014-12-25

_ リーダブルコード 社内勉強会その4

今回の範囲:10章 無関係の下位問題を抽出する、11章 一度に1つのことを

  • 発表担当でした。
  • プレゼンツール被らない縛りを継続。 reveal.js + markdownで書いた。
  • やりすぎよくない。 YAGNI
  • vote の例題は、コメント付けて何とかしようとすると余計ひどくなりそうな感じがあり、いい例。

2014-12-26

_ 仕事納め

ぬいぐるみを机の上に並べて来たので年明けに片付けないと(風邪ひいて休んだりしませんように)。 軽く飲みに行っておしまい。

_ シクラメン

家に帰ったら大きな箱が届いていた。開けてみるとお花屋さんをしてる友達からの贈り物でした。


2014-12-29

_ [windows] ミニダンプ

先日会社で「ミニダンプかー。情報ないなー」という言葉を耳にして、その言葉の用法は違うと知ったかぶりして言おうとしたが、実際のところ詳細を理解していない気がしたのでその場では黙っておいた。

MSDN:Minisumps

 The name "minidump" is misleading, because the largest mini dump files
 actually contain more information than the "full" user-mode dump.

とあるように、誤解を招く用語ではあるが、ミニダンプであるなら必ずしも情報が少ないというわけではなく、どういう情報を付けるかを指定でき、その指定によって情報が多かったり少なかったりする。

具体的に見るため、対象プロセスをwindbgとして、.dump /m と.dump /ma でダンプを取ってみる:

 対象プロセスを起動
 >"c:\Program Files (x86)\Windows Kits\8.1\Debuggers\x64\windbg.exe
 アタッチして/mと/maでそれぞれダンプ保存してデタッチ
 >"c:\Program Files (x86)\Windows Kits\8.1\Debuggers\x64\cdb.exe" -pn windbg.exe -c ".dump /m m.dmp;.dump /ma ma.dmp;.detach;q"
 ...
 0:001> cdb: Reading initial command '.dump /m m.dmp;.dump /ma ma.dmp;.detach;q'
 Creating m.dmp - mini user dump
 Dump successfully written
 Creating ma.dmp - mini user dump
 Dump successfully written
 Detached
 quit:
 >dir
 ...
 12/29/2014  10:59 PM            24,209 m.dmp
 12/29/2014  10:59 PM        77,143,405 ma.dmp

保存されたダンプファイルのサイズを比べると全然違うので、情報量の差は歴然だが、実際何が違うのかを見てみる。

まず、どちらでも見れる情報から。各スレッドのスタックトレースは小さい方のダンプでも見れるので、例えばWERで飛んできたクラッシュ情報から、どこで落ちてるかといったことまでは読み取れる。

 >"c:\Program Files (x86)\Windows Kits\8.1\Debuggers\x64\cdb.exe" -z m.dmp -c "~*kbn;q"
 ...
 0:001> cdb: Reading initial command '~*kbn;q'

    0  Id: f68.ac0 Suspend: 1 Teb: 00007ff6`2dc0d000 Unfrozen
  # RetAddr           : Args to Child                                                           : Call Site
 00 00007ff6`2df085cb : 00000000`00000000 00000000`00000001 00000000`00000000 00000000`00000000 : user32!NtUserWaitMessage+0xa
 01 00007ff6`2df0f21d : 00000000`00000001 00000000`00000000 00007ff6`2dec1188 00000000`00000000 : windbg!wmain+0x50f
 02 00007ff9`8d4016ad : 00000000`00000000 00000000`00000000 00000000`00000000 00000000`00000000 : windbg!HtmlHelpW+0x399
 03 00007ff9`8d594409 : 00000000`00000000 00000000`00000000 00000000`00000000 00000000`00000000 : kernel32!BaseThreadInitThunk+0xd
 04 00000000`00000000 : 00000000`00000000 00000000`00000000 00000000`00000000 00000000`00000000 : ntdll!RtlUserThreadStart+0x1d

 #  1  Id: f68.b0c Suspend: 1 Teb: 00007ff6`2dc0b000 Unfrozen
  # RetAddr           : Args to Child                                                           : Call Site
 00 00007ff9`8d601ac4 : 00000000`00000000 00000000`00000000 00000000`00000000 00000000`00000000 : ntdll!DbgBreakPoint
 01 00007ff9`8d4016ad : 00000000`00000000 00000000`00000000 00000000`00000000 00000000`00000000 : ntdll!DbgUiRemoteBreakin+0x34
 02 00007ff9`8d594409 : 00000000`00000000 00000000`00000000 00000000`00000000 00000000`00000000 : kernel32!BaseThreadInitThunk+0xd
 03 00000000`00000000 : 00000000`00000000 00000000`00000000 00000000`00000000 00000000`00000000 : ntdll!RtlUserThreadStart+0x1d
 quit:

一方で、ダンプファイルのサイズを見てわかるように、ヒープの情報なんかは大きい方にしかついていない。

 >"c:\Program Files (x86)\Windows Kits\8.1\Debuggers\x64\cdb.exe" -z ma.dmp -c "!heap;q"
 ...
 0:001> cdb: Reading initial command '!heap;q'
 Index   Address  Name      Debugging options enabled
   1:   ba95010000
   2:   ba94d90000
   3:   ba95230000
   4:   ba96b00000
 quit:

 >"c:\Program Files (x86)\Windows Kits\8.1\Debuggers\x64\cdb.exe" -z m.dmp -c "!heap;q"
 ...
 0:001> cdb: Reading initial command '!heap;q'
 HEAPEXT: Unable to get address of *ntdll!RtlpGlobalTagHeap.
 No heaps to display.
 You must specify the actual heap address since the
 array of process heaps is inaccessible
 quit:

この場合ヒープに辿り着くまでに蹴られているが、m.dmpの方では直接参照しても有用な情報がない(上が大きい方(/ma)のダンプ、下が小さい方(/m)のダンプ):

 >"c:\Program Files (x86)\Windows Kits\8.1\Debuggers\x64\cdb.exe" -z ma.dmp -c "!address ba95010000;q"
 ...
 Usage:                  Heap
 Base Address:           000000ba`95010000
 End Address:            000000ba`95052000
 Region Size:            00000000`00042000
 State:                  00001000        MEM_COMMIT
 Protect:                00000004        PAGE_READWRITE
 Type:                   00020000        MEM_PRIVATE
 Allocation Base:        000000ba`95010000
 Allocation Protect:     00000004        PAGE_READWRITE
 More info:              heap owning the address: !heap 0xba95010000
 More info:              heap segment
 More info:              heap entry containing the address: !heap -x 0xba95010000
 ...
 >"c:\Program Files (x86)\Windows Kits\8.1\Debuggers\x64\cdb.exe" -z m.dmp -c "!address ba95010000;q"
 ...
 Usage:                  <unknown>
 Base Address:           000000ba`94e40000
 End Address:            000000ba`96b8fc28
 Region Size:            00000000`01d4fc28
 State:                  <info not present at the target>
 Protect:                <info not present at the target>
 Type:                   <info not present at the target>
 Allocation Base:        <info not present at the target>
 Allocation Protect:     <info not present at the target>

その他、小さい方のダンプでは、!peb,!handle,.ttimeでも有用な情報を取れない:

 >"c:\Program Files (x86)\Windows Kits\8.1\Debuggers\x64\cdb.exe" -z m.dmp -c "!peb;q"
 ...
 0:001> cdb: Reading initial command '!peb;q'
 PEB NULL...
 quit:
 >"c:\Program Files (x86)\Windows Kits\8.1\Debuggers\x64\cdb.exe" -z m.dmp -c "!handle;q"
 ...
 0:001> cdb: Reading initial command '!handle;q'
 ERROR: !handle: extension exception 0x80004002.
     "Unable to read handle information"
 quit:
 >"c:\Program Files (x86)\Windows Kits\8.1\Debuggers\x64\cdb.exe" -z m.dmp -c ".ttime;q"
 ...
 0:001> cdb: Reading initial command '.ttime;q'
 Thread times not available
 quit:

以上、単にミニダンプと言っても、オプションによって含まれる情報量はいろいろである。

なお、 MSDN:Collecting User-Mode Dumps に記載されているDumpType,CustomDumpFlagsを調整するとアプリケーションクラッシュ時に自動取得されるダンプの種類を切り替えられるが、おそらく冒頭の「ミニダンプかー」はここの説明に由来するものではないかと思われる。 結論:誤解を与えない名前付けは重要。

_ 忘年会

高校の図書部の友達と。今回は大阪開催だったので電車で参加。森ノ宮で降りたらJRの駅が工事中でどこから入るんだーと少し悩んだりしたが、JR改札前にて、そもそも予定では高井田で乗り換えるはずだったことに気づく(ちょっと遠回りしてしまった)。その後は無事に辿り着き、家主の旦那さまのおいしいお料理をごちそうになりました。


2014-12-30

_ [checkio] reached level 14

Exec Quineを解いたところでレベルアップ。 Emacsが末尾に改行を足してくれるのと闘いつつ書いた。

_ [emacs] who sets require-final-newline?

C-hv require-final-newline すると

 require-final-newline is a variable defined in `files.el'.
 Its value is t
 Original value was nil
 Local in buffer exec_quine.py; global value is nil
 ...
 Certain major modes set this locally to the value obtained
 from `mode-require-final-newline'.

誰がセットしてるのか調べてみるのにまず C-hmして

 Python mode defined in `python.el':
 Major mode for editing Python files.

python.elのリンクをたどってソースを見てもそれらしきものはなくて、

 ;;;###autoload
 (define-derived-mode python-mode prog-mode "Python"
   "Major mode for editing Python files.

 \\{python-mode-map}"

とあるので C-hf prog-modeして継承元をたどって、

 prog-mode is an interactive compiled Lisp function in `prog-mode.el'.

prog-mode.elを見ると

 ;;;###autoload
 (define-derived-mode prog-mode fundamental-mode "Prog"
   "Major mode for editing programming language source code."
   (setq-local require-final-newline mode-require-final-newline)

みーつけた。

_ [python] 関数の説明

関数定義の先頭に書かれている説明文は __doc__ でアクセスできるようだ。例えば

 % python3
 Python 3.3.5 (default, Mar 21 2014, 01:54:25)
 [GCC 4.2.1 Compatible Apple LLVM 5.1 (clang-503.0.38)] on darwin
 Type "help", "copyright", "credits" or "license" for more information.
 >>> print(sum.__doc__)
 sum(iterable[, start]) -> value

 Return the sum of an iterable of numbers (NOT strings) plus the value
 of parameter 'start' (which defaults to 0).  When the iterable is
 empty, return start.

help(sum)としても同じ内容が見れる。


2014-12-31

_ 2014前半のふりかえり

  • コード書かないお仕事がさらに多くなった。
    • お客さんの話を聞いたり説明したりが中心に。
    • どうしたらデグレせずに価値を届けられるかをチームのみんなで考えました。
  • すごいHaskell読書会2周目に参加。
    • 参加された方々といい出会いをしました。
      • 関数型道場とかScala勉強会に参加するきっかけにもなりました。
      • Functional Programming in Scala という興味深い本を紹介してもらって読み始めました。
    • 今年一年のペースメーカー的存在でした。参加者の方々に感謝。
  • CheckIOに参加してPython の練習。
    • 良質な課題がたくさんあって、時間の開いた時に頭の体操ができました。

_ 2014後半のふりかえり

  • コード書くお仕事に戻った。
    • 未熟すぎるのでコード書いて技術力を高めたい!という希望を上司に伝えたのと異動の話が入れ違いだったと思う。
    • 考えていたことが無意識で漏れ出ていたのかもしれない。
  • 会社で リーダブルコード の勉強会を始めた。
    • 良い本を読み返す機会を与えてくれた主催者のS氏に感謝。
    • 製品コードから課題を抽出して、参加したみんなでワイワイ議論できた。