Yoichi's diary
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
2014-12-08
_ 同じファイルを複数ウィンドウで表示
「リーダブルコード」の4.2の、関数呼び出しの書式を揃えてコメントを一つにまとめるという話を読み返していて、「こう書いてて呼び出しが多くなってきて1ページに収まらなくなったら、コメントのところを表示しながら実装箇所を見れないといかんよな」と思ったので、同じファイル内の複数の箇所を同時に参照したいときの、いろいろなエディタでのやり方を調べてみた。- Emacs: C-x 2, C-x o (Multiple Windows)
- vim: :split, C-w w (ウィンドウの分割)
- Visual Studio: エディタ右上のつまみをドラッグ (.NET TIPS VS.NETでファイルの異なる個所を同時に表示するには?)
- Sublime Text: Alt-Shift-8, New View into File(Sublime Text2 で同一ファイルを 2 分割する方法)
2014-12-09
_ 名著『リーダブルコード ―より良いコードを書くためのシンプルで実践的なテクニック 』を解説者と一緒に読み解こう
Schooの授業を受けてみた。コードを読む人の気持ちになって考えて書くというのは、意識はしているつもりでいるものの、なかなかうまくできている気がしなくて日々悩んでいる。授業の中では、「ドキュメントを書いてみる」、「書いたライブラリを使う側のコードを書いてみる」のがよいのではというアドバイスをされていた。
最近やっている仕事では、自分たちで過去に書いたライブラリと、過去には中身まで見ていなかったがそれを使うアプリがあり、アプリとライブラリの両方を拡張していく作業をしていて、その中でアプリ側の実装を読んでいくと、ところどころ無理を強いちゃっているなという箇所が出てきている。使う側の視点が不足してたんだなと反省しつつ、せめて拡張部分は無理のないようにと、ある時はアプリ側の開発者の帽子、ある時はライブラリ側の開発者の帽子と、2つの帽子を交互にかぶりながら対応していこうとしてる。
あと、コードを読む時にいいところを探そうというのは、意識して行こうと思う。
2014-12-11
_ リーダブルコード 社内勉強会その2
今回の範囲:4章 美しさ、5章 コメントすべきことを知る、6章 コメントは正確で完結に
読む人が「えっ」と思う所にコメントを書くべきだけど、コード書いている自分でなかなか気づけない。どうしたらよいか?という疑問に対しては、レビューされるという意識を持って書くと、質問されそう、突っ込まれそうなところを自然と想像するのでいいという話があった。確かに気を引き締めて自身でコードを見ると、その後レビューするレビューア(別の人)よりも厳しい目で見れる部分があるなと思った。
あと今回の例題では、先日の須藤さんの講義で聞いたことを受け、手本になるようないいコードをなるべく集めるようにしてみたところ、前向きな話ができてよかったと感じた。
2014-12-13
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-26
_ 仕事納め
ぬいぐるみを机の上に並べて来たので年明けに片付けないと(風邪ひいて休んだりしませんように)。 軽く飲みに行っておしまい。
_ シクラメン
家に帰ったら大きな箱が届いていた。開けてみるとお花屋さんをしてる友達からの贈り物でした。
2014-12-29
_ [windows] ミニダンプ
先日会社で「ミニダンプかー。情報ないなー」という言葉を耳にして、その言葉の用法は違うと知ったかぶりして言おうとしたが、実際のところ詳細を理解していない気がしたのでその場では黙っておいた。
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 の練習。
- 良質な課題がたくさんあって、時間の開いた時に頭の体操ができました。