[WIP] プログラマ・エンジニアとして覚えておきたいと思ったこと


プログラマ・エンジニアとして覚えておきたいと思ったこと

受け入れるのは寛容に、送り出すのは厳格に

UNIXの思想や、インターネットの原則の一つ。

3.9 Be strict when sending and tolerant when receiving.

なんでも寛容に受け入れればよいというわけではないけれど。

パレートの法則

いわゆる80対20の法則。
80%の利益が、20%の人からもたらされている、とかいうアレ。
数字の80とか20にはあまり意味がないので、実際には1%のものが90%を占めている、といったこともある。

元は経営方面の話からきているのだと思うけど、いろいろな分野に応用される。

一番実感できるのは、性能向上などで実測してみたら、ごくごく一部の機能が処理時間の大半を占めていたりする場合。

ただし「主要な少数に注力しろ」という解釈だけではないと思われる。

  • ロングテール商法
  • 神は細部に宿る

マズローのハンマー

ハンマーを持つ人には、すべてが釘に見える

便利な道具を手に入れたり、新しい方法を知ると、どんな問題に対してでもそれを使ってみたくなる、という意味。
自戒を込めて。適材適所。

プログラマの三大美徳

  • 怠惰(Laziness) - 効率や再利用性の重視
  • 短気(Impatience) - 処理速度の追求
  • 傲慢(Hubris) - 品質にかける自尊心

【参考】wikipedia: プログラマの三大美徳

見える化、あるいはカンバン

  • 最新の正しい情報を
  • 大きくわかりやすく書いて
  • 一か所にまとめて
  • みんなで見ることができる

UNIX哲学

伽藍とバザール

誤字脱字

誤字脱字はなかなか無くならない(気づかない)。

こんちには みさなん おんげき ですか?
わしたは げんき です。 この ぶんょしう は いりぎす の ケブンッリジ だがいく の けゅきんう の けっか にんんげ は もじ を にしんき する とき その さしいょ と さいご の もさじえ あいてっれば じばんゅん は めくちちゃゃ でも ちんゃと よめる という けゅきんう に もづいとて わざと もじの じんばゅん を いかれえて あまりす。
どでうす? ちんゃと よゃちめう でしょ?
ちんゃと よためら はのんう よしろく

  • 上記はネットのどこかで拾ったもの
  • 1次情報源は不明
  • ケンブリッジ大学うんぬんについての真偽は怪しい
  • wikipedia: タイポグリセミア

車輪の再発明

基本的には避けるべきだけど、学習のため(理解を深めるため)にあえてやることも重要かな。

枝刈り

探索アルゴリズムで、無駄な探索を早めに打ち切ること。
アルゴリズム的にも有効だけど、日ごろの思考・理解などでも重要かと。

例えば、副作用のない純粋関数、イミュータブル、変更不能変数(定数)などは、考えなくてよいことが明確なため、理解しやすくなっている。

分割統治法

大きな問題を小さな問題に分割して解決する方法、アルゴリズム。

例えば、32bitの整数型のビット列を左右反転させるとした場合、以下のような方法がある(ベストなコードではないけど)。

public static int reverse(int data) {
    // 16bitづつ入れ替える
    data = ((data >>> 16) & 0x0000ffff) | ((data << 16) & 0xffff0000);
    // 8bitづつ入れ替える
    data = ((data >>> 8) & 0x00ff00ff) | ((data << 8) & 0xff00ff00);
    // 4bitづつ入れ替える
    data = ((data >>> 4) & 0x0f0f0f0f) | ((data << 4) & 0xf0f0f0f0);
    // 2bitづつ入れ替える
    data = ((data >>> 2) & 0x33333333) | ((data << 2) & 0xcccccccc);
    // 1bitづつ入れ替える
    data = ((data >>> 1) & 0x55555555) | ((data << 1) & 0xaaaaaaaa);
    return data;
}

(同様の考え方で、64bit整数型を8x8のビットイメージとして、90度回転させる、といったことも可能)

クイックソートや二分探索も、分割統治法を使っているといえる。
アルゴリズム以外にも、活用できることは多いかも。

処理量のオーダー

例えば1000件のデータを処理するのに100ミリ秒かかるとして、100万件のデータを処理するのにどれぐらいかかるか?

処理量のオーダーが $O(n)$ なら1000倍ぐらいで100秒ぐらいかなと思うけど(実際に1000倍かどうかはとりあえず置いておく)、オーダーが $O(n^2)$ だと 0.1秒×1000×1000倍で、10万秒ぐらい(1日以上。場合によっては数日)かかる計算になります。

可能なら $O(n \log n)$ ぐらいのオーダーにしたいですよね。
(一般的なアルゴリズムで、速いソートが $O(n \log n)$ で、遅いソートが $O(n ^ 2)$ になる)

O(1) < O(\log n) < O(n) < O(n \log n) < O(n^2) < O(n^3) \ll O(2^n) < O(3^n) \ll O(n!)

性能向上・性能対策

プログラムの性能(処理速度)が悪い場合、がむしゃらになんでも最適化(高速化)をしてもなかなか結果に結びつかないことが多い。
プロファイラーなどでボトルネックのなっている個所を洗い出して、そこを重点的に対策する必要がある。

それ以上に効率的な対策は、アルゴリズムや処理方法を見直すことだと思う。

  • 前述 UNIX哲学 の中の「Cプログラミングに関する覚え書き」
    • 推測するな、測定せよ
  • 「早すぎる最適化は諸悪の根源」ドナルド・クヌース
  • パレートの法則

不具合

時として、思いもよらない不具合が起きることがある。

あるいは、相関関係と因果関係の違いは分かりにくい、ともいえるのかも?

簡単そうに見えても奥が深いことが多い

データ

まとめ系

その他

  • RESTFul
  • The Twelve-Factor App
  • Git Flow, Github Flow
  • ボーイスカウトの原則:来た時よりも美しく
  • 1年後の自分は他人
  • KISS, DRY, COC, YAGNI, PIE, ...
  • Lie-to-children
  • などなど