RHEL7でスナップショットとり放題設定をためしたメモ
インストール
状態を確認
[root@localhost log]# lsblk
NAME MAJ:MIN RM SIZE RO TYPE MOUNTPOINT
sda 8:0 0 20G 0 disk
├─sda1 8:1 0 500M 0 part /boot
└─sda2 8:2 0 16.4G 0 part
├─rhel-swap 253:0 0 2G 0 lvm [SWAP]
├─rhel-pool00_tmeta 253:1 0 12M 0 lvm
│ └─rhel-pool00-tpool 253:3 0 12G 0 lvm
│ ├─rhel-root 253:4 0 12G 0 lvm /
│ └─rhel-pool00 253:5 0 12G 0 lvm
└─rhel-pool00_tdata 253:2 0 12G 0 lvm
└─rhel-pool00-tpool 253:3 0 12G 0 lvm
├─rhel-root 253:4 0 12G 0 lvm /
└─rhel-pool00 253:5 0 12G 0 lvm
sr0 11:0 1 3.6G 0 rom
[root@localhost log]# lvs
LV VG Attr LSize Pool Origin Data% Meta% Move Log Cpy%Sync Convert
pool00 rhel twi-aotz-- 12.00g 9.38 5.18
root rhel Vwi-aotz-- 12.00g pool00 9.38
swap rhel -wi-ao---- 2.00g
[root@localhost log]# lvdisplay /dev/rhel/pool00
--- Logical volume ---
LV Name pool00
VG Name rhel
LV UUID vuooGK-VHow-JfAo-cPQb-Egf1-fCk4-qRpLqK
LV Write Access read/write
LV Creation host, time localhost, 2015-05-15 19:15:03 +0900
LV Pool metadata pool00_tmeta
LV Pool data pool00_tdata
LV Status available
# open 2
LV Size 12.00 GiB
Allocated pool data 9.38%
Allocated metadata 5.18%
Current LE 3072
Segments 1
Allocation inherit
Read ahead sectors auto
- currently set to 8192
Block device 253:3
lvcreate --permission r --snapshot --name snapshot rhel/root
snapper設定の作成
[root@localhost ~]# snapper create-config -f 'lvm(xfs)' /
さらに設定一覧が /etc/sysconfig/snapper にあるのでここに設定名が追加されます。
[root@localhost log]# snapper list-configs
Config | Subvolume
-------+----------
root | /
snapshot作成
[root@localhost log]# snapper create
[root@localhost log]# snapper list
Type | # | Pre # | Date | User | Cleanup | Description | Userdata
-------+---+-------+--------------------------+------+---------+-------------+---------
single | 0 | | | root | | current |
single | 9 | | Mon May 18 18:15:10 2015 | root | | |
[root@localhost log]# lvs
LV VG Attr LSize Pool Origin Data% Meta% Move Log Cpy%Sync Convert
pool00 rhel twi-aotz-- 12.00g 10.00 5.73
root rhel Vwi-aotz-- 12.00g pool00 10.00
root-snapshot9 rhel Vri---tz-k 12.00g pool00 root
swap rhel -wi-ao---- 2.00g
スナップショットのマウント
.snapshotディレクトリ以下に適当にmountされます。
[root@localhost ~]# snapper mount 10
[root@localhost ~]# df
Filesystem 1K-blocks Used Available Use% Mounted on
/dev/mapper/rhel-root 12571648 1226516 11345132 10% /
devtmpfs 1931348 0 1931348 0% /dev
tmpfs 1941204 0 1941204 0% /dev/shm
tmpfs 1941204 8580 1932624 1% /run
tmpfs 1941204 0 1941204 0% /sys/fs/cgroup
/dev/sda1 508588 168516 340072 34% /boot
/dev/mapper/rhel-root--snapshot10 12571648 1193528 11378120 10% /.snapshots/10/snapshot
snapshot間の差分
[root@localhost ~]# snapper create -t pre
[root@localhost ~]# ls
anaconda-ks.cfg hoge lvmdump-localhost.localdomain-20150515103428.tgz
[root@localhost ~]# rm hoge
rm: remove regular empty file ‘hoge’? y
[root@localhost ~]# snapper list
Type | # | Pre # | Date | User | Cleanup | Description | Userdata
-------+----+-------+--------------------------+------+---------+-------------+---------
single | 0 | | | root | | current |
single | 9 | | Mon May 18 18:15:10 2015 | root | | |
pre | 10 | | Mon May 18 18:18:32 2015 | root | | |
[root@localhost ~]# snapper create -t post --pre-number=10
[root@localhost ~]# snapper list
Type | # | Pre # | Date | User | Cleanup | Description | Userdata
-------+----+-------+--------------------------+------+---------+-------------+---------
single | 0 | | | root | | current |
single | 9 | | Mon May 18 18:15:10 2015 | root | | |
pre | 10 | | Mon May 18 18:18:32 2015 | root | | |
post | 11 | 10 | Mon May 18 18:19:42 2015 | root | | |
[root@localhost ~]# snapper status 10..11
-..... /root/hoge
c..... /var/log/messages
c..... /var/log/snapper.log
差分対象の制限(フィルタ)
/var/log/*
[root@localhost ~]# snapper status 10..11
-..... /root/hoge
undo
[root@localhost ~]# snapper undochange 10..11
create:1 modify:0 delete:0
TODO
freeの出力が大幅改善された話
最近freeコマンドを叩くとこんな感じで出力されます。
$ free
total used free shared buff/cache available Mem: 20209620 3859396 6594188 502492 9756036 15323144 Swap: 32767996 0 32767996
availableってなんでしょう? そして -/+ buffers/cache の行がなくなっています。
その背景をちらっと紹介します。
最近linuxの3.14で/proc/meminfo に MemAvailable というフィールドが追加されました。RHEL7.0や6.6にもバックポートされています。(RHEL6.6では互換性に配慮してデフォルトではdisableされています)
http://git.kernel.org/cgit/linux/kernel/git/torvalds/linux.git/commit/?id=34e431b0ae398fc54ea69ff85ec700722c9da773
/proc/meminfo: provide estimated available memory Many load balancing and workload placing programs check /proc/meminfo to estimate how much free memory is available. They generally do this by adding up "free" and "cached", which was fine ten years ago, but is pretty much guaranteed to be wrong today. It is wrong because Cached includes memory that is not freeable as page cache, for example shared memory segments, tmpfs, and ramfs, and it does not include reclaimable slab memory, which can take up a large fraction of system memory on mostly idle systems with lots of files. Currently, the amount of memory that is available for a new workload, without pushing the system into swap, can be estimated from MemFree, Active(file), Inactive(file), and SReclaimable, as well as the "low" watermarks from /proc/zoneinfo. However, this may change in the future, and user space really should not be expected to know kernel internals to come up with an estimate for the amount of free memory. It is more convenient to provide such an estimate in /proc/meminfo. If things change in the future, we only have to change it in one place. Signed-off-by: Rik van RielReported-by: Erik Mouw Acked-by: Johannes Weiner Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds
このフィールドは「だいたいこのくらいはswap発生させずにアプリケーションがallcoateできそう」というメモリ量の推定です。
procps-ngに含まれるfreeコマンドがbuffer や cacheとして使われているメモリをfreeに足して表示する機能があった(過去形)ことも手伝って、これらを単純に全て「カーネルがパフォーマンス改善のために未使用メモリをうまいこと使っている」と見做してシステム管理している人が多くいます。しかしこの見方は正しくありません。buffer や cacheは非常に重要で、もしこれらが0になってしまえばシステムは全く稼動できないでしょう。どれくらい存在すれば十分なパフォーマンスがでるかも、アプリケーションの特性により非常に大きくかわります。
そこでもうちょっとましな推定値をつくろうということで導入されたのがMemAvailableです。現在の実装ではかならずしもカーネルの中でこの推定をする必要はないのですが、将来的にカーネルのメモリ管理のしくみが変わっても同じように利用できるよう追加されました。
さて、これにともなってprocps-ngも3.3.10で更新されています。このprocps-ng 3.3.10はRHEL7.1に含まれています。
availableフィールドを追加 https://gitorious.org/procps/procps/commit/ba6396f886f1a9911221e1c7c4b66dc75acb6948
MemAvailableがなくても同等の計算を他のフィールドからするfallback https://gitorious.org/procps/procps/commit/b779855cf15d68f9038ff1809db18c0788e9ae70
MemAvailableはあくまでざっくりした推定値なので、既存の統計情報を足したり引いたり適当な割り算をしたりして出しています。なので、その元になっているフィールドが提供されているlinux 2.6.27以降であれば同じような計算をしてavailableを出す機能です。
-----------------------------------------------------------
/* zero? might need fallback for 2.6.27 <= kernel
if (!kb_main_available) {
if (linux_version_code < LINUX_VERSION(2, 6, 27))
kb_main_available = kb_main_free;
else {
FILE_TO_BUF(VM_MIN_FREE_FILE, vm_min_free_fd);
kb_min_free = (unsigned long) strtoull(buf,&tail,10);
watermark_low = kb_min_free * 5 / 4; /* should be equal to sum of all 'low' fields in /proc/zoneinfo */
mem_available = (signed long)kb_main_free - watermark_low
+ kb_inactive_file + kb_active_file - MIN((kb_inactive_file + kb_active_file) / 2, watermark_low)
+ kb_slab_reclaimable - MIN(kb_slab_reclaimable / 2, watermark_low);
if (mem_available < 0) mem_available = 0;
kb_main_available = (unsigned long)mem_available;
}
}
-----------------------------------------------------------
もはや不要となった free: remove -/+ buffers/cacheの削除 https://gitorious.org/procps/vnwildman-procps/commit/f47001c9e91a1e9b12db4497051a212cf49a87b1
そういうわけで、freeコマンドの出力が劇的に改善されたのでした。
IPアドレスのvalid lifetime
ip addr とかで
3: em1:mtu 1500 qdisc pfifo_fast state UP group default qlen 1000
link/ether d4:3d:7e:dc:c8:ad brd ff:ff:ff:ff:ff:ff
inet 10.64.193.115/23 brd 10.64.193.255 scope global dynamic em1
valid_lft 82874sec preferred_lft 82874sec
inet6 fe80::d63d:7eff:fedc:c8ad/64 scope link
valid_lft forever preferred_lft forever
みたいになっているとき、em1のアドレスに有効期限がついている。
valid_lft 82874secが有効期限の設定。
この期限が切れた時には、kworkerがアドレスを切り離す。
これを設定しているのは /usr/sbin/dhclient-script で、以下みたいなコードで設定している。
ip -4 addr add ${new_ip_address}/${new_prefix} broadcast ${new_broadcast_address} dev ${interface} \valid_lft ${new_dhcp_lease_time} preferred_lft ${new_dhcp_lease_time} >/dev/null 2>&1
systemd-udevdによるNIC命名とbiosdevnameがまざって混乱する件
最近のsystemd-udevdはlinuxのネットワークインタフェース名を設定します。それにともない特にRHEL界隈でNIC命名規則が複雑になってきたので紹介します。。
問題: linuxカーネルはNICの名前をドライバ初期化順につけるので名前とNICの対応が安定しない。再起動毎に順序がかわる可能性もある。
これに対して過去から最近までいろいろな手法で対策がとられています。
ユーザが明示的に指定する
MAC アドレスなどの識別子とインタフェース名を設定ファイルで明示して指定する。こんなかんじ。
DEVICE=eth1 HWADDR=D4:85:64:01:46:9E ONBOOT=yes
Predictable Network Interface Name
くわしくはsystemd本家のwikiにみっちり書いてますが、ざっくりまとめるとハードウェアの物理的な位置やバス上のアドレスを根拠にした、安定した名前をつけます。
命名規則: デバイスの種類(Ethernetならen, wirelesslanならwl) + ファームウェアでの場所情報(スロット番号またはPCIバスの番号) [+VF番号など]
例: ens0
Consistent Device Naming by biosdevname
安定した名前づけの仕組みとしては、biosdevnameという別の実装があります。これは最近のFedoraや、RHEL6, 7でDell製ハードウェアの場合に利用されます。
http://linux.dell.com/biosdevname/
SMBIOSというファームウェアの規格で「オンボードの1番」や「拡張カードスロットの2番」のような場所情報を提供し、これを元にNICの名前を作ります。
例: em1
Persistent Net
これらの物理的な位置を利用する命名方法が登場する前から利用されているpersistent-netとよばれる仕組みがあります。
これは一旦linuxカーネルに適当な名前づけをされたあとに(これが物理的な配置とは無関係になっていることには目をつぶり)、次回の起動からは同じNICに同じ名前をつけるようにするため、MACアドレスとインタフェース名の対応づけをudevのルールとして永続化する仕組みです。
この対応づけは/etc/udev/rules.d/70-persistent-net.rules に保存されます。
RHEL7や最近のFedoraでpersistent-netのルール作成はされませんがRHEL6までで作成されたものをアップグレードした場合はひきつづき有効です。
こんがらがるので以下にまとめます。優先順位自体は最近のFedoraのものと同じですが、デフォルトでの有効無効が環境によってバラバラです。
最近のFedora: ユーザの指定 > persistent-net > biosdevname > systemd > 古典的な名前づけ
RHEL6 on Dell: ユーザの指定 > persistent-net > biosdevname > 古典的な名前づけ
RHEL6 on not Dell: ユーザの指定 > persistent-net > 古典的な名前づけ
RHEL7 on Dell: ユーザの指定 > persistent-net > biosdevname > systemd > 古典的な名前づけ
RHEL7 on not Dell: ユーザの指定 > persistent-net > systemd > 古典的な名前づけ
NIC名前例:
古典的な名前づけ: eth0 (最初にeth%d って名前で命名されたNIC)
各自動設定の止め方
systemdのNIC命名: カーネルのコマンドラインに net.ifnames=0
biosdevname: カーネルのコマンドラインに biosdevname=0
persistent-net: /etc/udev/rules.d/70-persistent-net.rulesから該当する行を消す
udevのルールの比較
# 以下RHEL7betaをためした人むけ
RHEL7 public betaを確認するとベンダにかかわらず on Dellのようになっているのですが、RHEL7RCでは上記のように動作が修正されています
なぜ cdromグループに入っていないユーザーがCD, DVDを焼けるか、あるいははじめてのsystemd-logind
事前の予想
-
/dev/cdrom あたりはrootユーザ、cdromグループになっている
-
使えるユーザはcdromグループに入っているから使える
確認と謎
dragon:~$ ls -l /dev/cdromlrwxrwxrwx 1 root root 3 May 2 03:07 /dev/cdrom -> sr0
dragon:~$ ls -l /dev/sr0brw-rw----+ 1 root cdrom 11, 0 May 2 03:07 /dev/sr0
dragon:~$ iduid=1000(kankun) gid=1000(kankun) groups=1000(kankun),24(cdrom),25(floppy),29(audio),30(dip),44(video),46(plugdev),105(scanner),109(bluetooth),111(netdev)
[kankun@snake ~]$ id uid=1000(kankun) gid=1000(kankun) groups=1000(kankun),10(wheel) context=unconfined_u:unconfined_r:unconfined_t:s0-s0:c0.c1023
brw-rw----+ 1 root cdrom 11, 0 May 2 03:07 /dev/sr0
dragon:~$ getfacl /dev/sr0getfacl: Removing leading '/' from absolute path names# file: dev/sr0# owner: root# group: cdromuser::rw-user:kankun:rw-group::rw-mask::rw-other::---
誰がこのACLを設定しているの?(タイトルでネタバレ)
-
今のログインユーザだから(pam?)
-
インストーラで作成したアカウントだから何か特別に設定が書かれている(どこぞの設定ファイルがudevのルールから参照されてる?)
-
GNOMEデスクトップユーザむけのなにかが動いている(udisksとか??)
getfacl: Removing leading '/' from absolute path names# file: dev/sr0# owner: root# group: cdromuser::rw-group::rw-mask::rw-other::---
getfacl: Removing leading '/' from absolute path names# file: dev/sr0# owner: root# group: cdromuser::rw-user:kankun:rw-group::rw-mask::rw-other::---
systemd-l 683 root 5r REG 0,15 4096 4386 /sys/devices/virtual/tty/tty0/active
systemd-logindによるACL設定
dir = opendir("/run/udev/static_node-tags/uaccess");
# optical drivesSUBSYSTEM=="block", ENV{ID_CDROM}=="1", TAG+="uaccess"
$ ls /run/udev/tags/uaccessb11:0 c10:232 c116:1 c116:10 c116:11 c116:12 c116:2 c116:3 c116:33 c116:4 c116:5 c116:6 c116:7 c116:8 c116:9 c189:257 c189:258 c189:259 c189:260 c189:385 c21:2 c226:0 c81:0
1. ログイン時のACL設定
2. VTの状態によるACL設定
3. udevdによるACL設定
TAG=="uaccess", ENV{MAJOR}!="", RUN{builtin}+="uaccess"
はじめの疑問にもどる
/proc/cpuinfoを目で読むのがつらい
最近のコンピュータだとCPUのコア数やスレッド数が多いので/proc/cpuinfoを直接読むよりまとめて出力してくれるlscpuやhwlocをつかったほうがよい。
最近コア数とか多いですね。デスクトップでもCore i7だと8スレッドとかありますしサーバだと4ソケット40コア80スレッドとかあります。
CPUがどういう構成なのか知りたい時は /proc/cpuinfo や /sys/devices/system/cpu/* を読むことが多いですが表示が冗長なのでつらいです。そこで適当にまとめて表示してくれるコマンドが便利です。
lscpuはCPUのキャッシュ構成とか、ソケット-コア-スレッドの個数の関係がわかります。実機で数回実行するとわかりますがCPU MHzのところは実際の周波数にあわせてちょいちょい変わるのでアテになりません。
出力はこんなかんじ:
$ lscpu
Architecture: x86_64
CPU op-mode(s): 32-bit, 64-bit
Byte Order: Little Endian
CPU(s): 8
On-line CPU(s) list: 0-7
Thread(s) per core: 2
Core(s) per socket: 4
Socket(s): 1
NUMA node(s): 1
Vendor ID: GenuineIntel
CPU family: 6
Model: 58
Stepping: 9
CPU MHz: 1802.000
BogoMIPS: 6784.54
Virtualization: VT-x
L1d cache: 32K
L1i cache: 32K
L2 cache: 256K
L3 cache: 8192K
NUMA node0 CPU(s): 0-7
hwlocは本来はNUMA環境などをうまく使うために適切なtaskset等を生成したりするためのツールセットなのですが、今回は表示してくれるところだけ見ます。グラフィカルなのが好きな人はいいんじゃないですかね。
$ hwloc-ls -p
以下はしばらく前にとった4ソケットマシンでのhwloc-lsの出力。「でかい!」ってことしかわからない気もします。。
プログラマ格言(2006)
* PHPを笑うものはPHPに泣く
* 意味: 「PHPなんてまともなプログラミング言語じゃないよ」と笑っていたら仕事でPHPを触るはめになってしかも既存のソースが汚かったりして泣く。
* 教訓: 好き嫌いを通せるようにえらくなれ。
* ソースが知れる
* 意味: 変な挙動をするソフトをさわっていると、動き方から間違ってるパターンと作った人のレベルがなんとなく透けて見える。
* 教訓: どうやったらうまく動くか探すのも仕事のうちらしい。
* ひいきのwiki倒し
* 意味: 「wikiはすばらしいツールですよ!」 と、とにかくwikiを導入してメンテ不良のページを大量につくってしまう。
* 教訓: 情報共有ツールは使う人のメンテナンス能力が一番のネック。
* ライブラリからボタ餅
* 意味: 延々ぐぐってみつからなかった情報がライブラリのソースであっさりみつかった。
* 教訓: ライブラリのソースは貴重な情報源。
* UMLの大木
* 意味: やたら継承ばっかりしていてすごい大木になっているクラス図を見てげっぷがでる。
* 教訓: 実装の再利用は依存関係の拡大に注意。
* 要求仕様と秋の空
* 意味: 要求仕様は秋の空のようにかわりやすい。
* 教訓: わかってるつもりの人が一番の危険人物。
* KnuthもTeXの誤り
* 意味: あのKnuth大先生ですらTeXで何個かバグを作り込んでしまったように完璧ではない。
* 教訓: 我々はプログラムにバグを必ず作り込んでしまう。
* とりつくcoreもない
* 意味: 反応なくなったから再起動したよ、とか運用してる人に言われたけどログは正常処理しかでてないしcoreはないしどうにもしようがない。
* 教訓: 何もないとこまるときは、backtrace吐いてくれるようにしとくだけでもだいぶしあわせ。
* 臭いバグに蓋をする
* 意味: バグっぽい挙動の原因を追及せずにとりあえずのworkaroundなパッチを書いてごまかす。
* 教訓: 「発現しなければバグではない」が通用{する|しない}世界もある。
* IDE屋のvi使い
* 意味: 客にはIDEを売るけど自分はviでソースを書く。
* 教訓: 使いやすそうなものと使いやすいものは別
* コードは一日にして成らず
* 意味: まともなコードは何年もかけて細かいノウハウや互換性対策などが積み重なっている。読んですぐ書けそうな気がしてもなかなかすぐには同等のものはできない。
* 教訓: 「既存のコードを全部捨ててやりなおし」はけっこう大変。
* 大山鳴動して虫が一匹
* 意味: 大騒ぎになる酷い障害も、原因はくだらないバグ1個だけだったりする。
* 教訓: 騒がなくていいからまず原因を調査。
* コピペも山のにぎわい
* 意味: 行数で単価が決まる案件では長いだけで無意味なコピペコードが良いということになってしまう。
* 教訓: 行単価という評価基準はヤバスギ。
* デザパタ読みのデザパタ知らず
* 意味: GoF本を読んだひとが「デザインパターン使うぜ!」と、設計に無理矢理デザインパターンを盛り込んで変な設計になってしまう。
* 教訓: 自然な適用をするためにはそれなりの修行が必要。
* 犬も歩けばバグに当る
* 意味: あんまり期待せずにウォークスルーをすると意外にバグがどんどんみつかって効率よかったりする。
* 教訓: 時には無心にコードを読むのもアリ。
* 一寸のバグにも五分の魂
* 意味: ちょっとしたバグにもそれを作り込んだプログラマの勘違いや仕様の誤解など、幅広く影響しそうな背景がある。
* 教訓: 「なんで?」を5回繰り返そう。
* デバガとハサミは使いよう
* 意味: デバッガに意外な便利コマンドがあったり、ソースを印刷した紙をハサミで切って並べてみるなど、プログラムを改良する方法にはさまざまなテクニックがある。
* 教訓: 既に知っている道具もちゃんと調べるといいことがあるかも。
* 地震,雷,火事,停電
* 意味: 人間以外にも怖いものはある。
* 教訓: このへんはマシンをデータセンターに置けばある程度避けられる。しかし人間は…!!
* バグぶつかるも他生の縁
* 意味: たまたまバグにぶつかっただけといっても、何かの縁なのだからバグレポートをしてあげよう。
* 教訓: バグからはじまる恋もある(ねーよ
* docを食らわばソースまで
* 意味: ドキュメントを調べだしたらついでとばかりにソースまでよんでしまう。しかも本題と関係ないコードが理解できなくてなやんだりする。
* 教訓: まずはFAQよんどこう。
* ソースに入ってはソースに従え
* 意味: 人のソースを変更するときはその人のコーディングスタイルに従って変更しよう。
* 教訓: コーディングスタイルへの過度のこだわりはよくない。
* 馬子にもGUI
* 意味: つまんないプログラムでもGUIをつけるとそれっぽくみえるらしい。
* 教訓: それっぽいだけかも。
* 溺れるものは2chをも捕む
* 意味: ハマってどうにもならないとき、2chの質問スレに頼る。
* 教訓: とりあえず情報の裏はとっとけ。
* 虎穴に入らずんばバグを得ず
* 意味: (よくわからなくて怖い)フレームワークやlibcやカーネルの中まで読みこまないとバグを完全につきとめることはできないこともある。
* 教訓: ソースさえ読めばそれなりにわかったりする。きにせずよんじゃえ。
* 書いたコードに手をかまれる
* 意味: ライブラリがおかしいのかとおもって延々調べても悪くなさそう。サンプルコードはちゃんと動く。まさかと思ってよくよく見ると自分が書いて大丈夫だと思ってたコードが間違えていた。
* 教訓: それがバグ。
* LL三年Web八年
* 意味: どんなにLLを覚えても結局はWeb技術そのものに明るくなるために何年もかかってしまうということ。
* 教訓: Webとブラウザ周辺は魔窟。
* 能あるプログラマは爪を隠す
* 意味: 有能なプログラマは、ほとんど「凄い」コードを書かないものである。
* 教訓: 平易なコードの作者を甘く見るな。
* 芸は身をHaskell
* 意味: Haskell みたいなマイナー言語を使えるとかえって職にあぶれない。
* 教訓: いろいろなプログラミング言語さわるとよい。
* 多言語は無言語
* 意味: いろんな言語にとりあえず手をだしてどれも中途半端にしかできないこと。
* 教訓: 言語の深いところはあまりかわらないので、一つを極めてから他に手をだすとよい。
* 案ずるより書くが易し
* 意味: どの実装方針がいいかなあ、と迷うより書いてしまうほうが簡単。
* 教訓: 迷ったら全部実装して比較。
* 悪設計は百年の不作
* 意味: 悪い設計を許してしまうとあらゆる場面で無駄な苦労をしてしまう。
* 教訓: 設計は経験と能力の両方がある人にお願いしよう。
* abで鯛を釣る
* 意味: 「ab(apache bench)で性能測定」のような仕事のほうが意外に金をとれたりする。
* 教訓: 自分的にたいしたことないスキルでも相手にとって価値があれば金になる。
* makeるが勝ち
* 意味: make一発でいろいろできるように自動化するとかなり便利
* 教訓: 客の仕事だけでなく自分の仕事も自動化しよう
* 転ばぬ先のテストケース
* 意味: 先にテストを書いておけば防げるバグは多い。
* 教訓: サボらずテストケースを書こう。