cloverrose's blog

Python, Machine learning, Emacs, CI/CD, Webアプリなど

ピープルウェア 第3版 感想

感想が、読書メーターに収まらなかったのでブログに書きます。

人月の神話の中でおすすめされていたので読みました。

ピープルウエア 第3版

Amazon.co.jp: ピープルウエア 第3版: トム・デマルコ, ティモシー・リスター, 松原友夫, 山浦恒央: 本

新しい知見が得られたり、面白かった章。特にためになったのが4章と34章(☆付けた)

1章 今日もどこかでトラブルが

ハイテクの幻影

IT企業で働いてるとついつい、全て自動化できるし、テクノロジーで解決できると思ってしまうけど、製品は置いておいて、確かに実際働いてる場所では人間臭いこと、社会学的なことがいっぱいだと再認識した。

☆4章 品位質第一・・・時間さえ許せば

自分が品質に拘るタイプなので、「プログラムの品質は開発者の自尊心と強く結びついてる」というのに非常に共感できた。チームの人の自尊心についても考えていけるようになろう。

13章 オフィス環境進化論

この本のオフィス環境の部分は、自分でどうこう出来る部分が少ないのであまり実りは無かったけど、この章で出てきた参考図書「時を超えた建築の道」が面白そうだなと思った。

あと、イヤホンで音楽聞いてると、音楽は右脳で聴いているので、作業をする左脳と競合しないからエラー発生率や開発速度はそこまで落ちないけど、右脳を使うひらめきが起きにくくなるというのが目からうろこだった。

22章 ブラックチームの伝説

読み物として面白い。プログラムのテストチームの話。

24章 続、チーム殺し:残業の予期しない副作用

残業すると、自分の人生の大事な時間が削られる。チームで長期間の残業を強制すると、育児などで残業をしない人への不満が募り、うまくいっていたチームも崩壊するという話。会社との雇用契約で結んだ時間ないしか個人を束縛してはいけないなと感じた。

26章 スパゲッティディナーの効果

読み物として面白い。本能的に優れたマネージャーの話。

27章 裃を脱ぐ

チームメンバーに無理にでも出張を組んで、会社から出させてあげる。

☆34章 変化を可能にする

ちょうど自分の今の体験と重なって、とても勉強になった。

  • 人は誰しも本質的に変化を嫌う
  • 変化に対する反応は以下のように分類され、自分が変化を起こそうとするときに、1.と3.は敵、真の味方は2.であるという話
  1. むやにみ忠実(全く質問もしない)
  2. 信じているが室もなり
    1. 懐疑論者(「証拠を見せろ」)
    2. 受身の傍観者 (「私に何か関係有ることがあるの?」)
    3. 反対者(変化への恐れ)
    4. 反対者(権力を失うことへの恐れ)
  3. 戦闘的な反対者(妨害したり破壊してやろう)
  • 変化を受け入れてもらうには論理的な意見を主張するのではなく、情緒的に、変化前の人たちに敬意を持って
  • 変化のモデルは古い状況-(他からの要素)->混乱-(アイデアの変形)->実践と統合->新しい状況という4つのフェーズがある

自分の体験というのは、CI・CDツールとしてChef(Ruby)に切り替えていくのが、Fabric(Python)の知識がある状態から、ChefとRubyという初心者に変わってしまうこととか、Chef導入に素直に賛成だった人より、懐疑論者だった自分(ChefとFabricの比較、Chefに移行して得られるメリットと学習コストのデメリットなどをまとめた)の方が、Chef以降に移ってからは、Kitchenのテストツールなどの調査など、真の味方なきがするなという部分。


自分はプログラミングも好きだけど、こういうソフトウェア開発における問題とかにも興味あるので非常に面白かった。

Pythonのjsonモジュールの便利機能

PythonJSONを読み書きする機会が割りとあったんですが、改めて調べたり、公式ドキュメントをちゃんと読んだら便利な機能を知ったのでメモしておきます。

jsonファイルの辞書を順番通りにloadしたい

設定ファイルとしてJSONを使っている時、普通にloadすると辞書の順番は保たれません。 でも、プログラム内部で設定を書き足してdumpするような場合、人間が書いた部分がごちゃごちゃになるとよろしくありません。

Pythonjsonモジュールでは次のようにすると順番通りに読み込めます。

import json
import collections


decoder = json.JSONDecoder(object_pairs_hook=collections.OrderedDict)
with open('conf.json') as conf_file:
    conf = decoder.decode(conf_file.read())

参考

最初に見つけた回答 Can I get JSON to load into an OrderedDict in Python? - Stack Overflow

公式ドキュメントでは以下のように書いてあります。

object_pairs_hook はオプションで渡す関数で、ペアの順序付きリストのデコード結果に対して呼ばれます。 object_pairs_hook の返り値は dict の代わりに使われます。この機能はキーと値のデコードされる順序に依存する独自のデコーダ (たとえば collections.OrderedDict() は挿入の順序を記憶します) を実装するのに使えます。 object_hook も定義されている場合は、 object_pairs_hook が優先して使用されます。

バージョン 2.7 で変更: object_pairs_hook のサポートを追加しました。

jsonをdumpするときにの行末空白(trailing whitespace)を無くしたい

出力するJSONが人が見る設定ファイルの場合、適切に改行やインデントを設定すると思います。 しかし、indentを設定すると行末空白が付いてしまい、設定ファイルをGitなどで管理するときに気になります。

次のようにseparatorsを指定してあげると行末空白を取り除くことができます。

with open('conf.json', 'w') as conf_file:
    json.dump(conf, conf_file, indent=4, separators=(',', ': '))

参考

最初に見つけた回答 Issue 16333: Trailing whitespace in json dump when using indent - Python tracker

公式ドキュメントでは以下のように書いてあります。

separators がタプル (item_separator, dict_separator) ならば、デフォルト区切り文字 (', ', ': ') の代わりに使われます。 (',', ':') が最もコンパクトな JSON の表現です。

サンプル

順番通りにloadして、新しい設定を追加して、行末空白なしで、元の順番通りに書き出す例

# -*- coding:utf-8 -*-
import json
import collections


decoder = json.JSONDecoder(object_pairs_hook=collections.OrderedDict)
with open('conf.json') as conf_file:
    conf = decoder.decode(conf_file.read())

conf['New.Key'] = 'append last'

with open('conf.json', 'w') as conf_file:
    json.dump(conf, conf_file, indent=4, separators=(',', ': '))

この2つは設定ファイル扱う上で今後は無くてはならない感じになりそうです。勉強になった!

EmacsでGithub flavorなMarkdownをプレビューできるようにする

markdown-modeを設定すると、C-c C-c pでMarkdownで書かれたファイルをHTMLに変換して、ブラウザで表示してくれるのでとっても便利です。

しかし、オリジナルのMarkdown.plを使うと表を変換できない、CSSを設定しないとすごくそっけないHTMLが表示されるという不便があります。

そこで、自分が好きな変換ツール(今回はPythonのgrip)を使うように設定しました。

手順

1. Markdown-modeをインストール

2. Gripをインストール

pip install grip

参考: GitHub Flavored Markdownを変換できるgripが便利だった - cloverrose's blog

3. PATHの通ったところに以下をmarkdownというファイル名で保存

#!/bin/sh
filename=$1
~/.virtualenvs/default/bin/grip --export ${filename} > /dev/null
cat ${filename%.*}.html

説明

  • gripにレンダリングサーバを建てるのではなく、HTMLを出力するように--exportオプションを指定
  • 実行時のExporting to hoge.htmlという標準出力が邪魔なので/dev/nullに
  • markdown-modeに変換結果を渡すためにcat

4. init.elに以下の設定ファイルを追加

;; markdown mode
;; markdownモード(gfm-mode Github flavor markdown mode)を拡張子と関連付けする
(autoload 'markdown-mode "markdown-mode"
   "Major mode for editing Markdown files" t)
(add-to-list 'auto-mode-alist '("\\.text\\'" . gfm-mode))
(add-to-list 'auto-mode-alist '("\\.markdown\\'" . gfm-mode))
(add-to-list 'auto-mode-alist '("\\.md\\'" . gfm-mode))

;; ファイル内容を標準入力で渡すのではなく、ファイル名を引数として渡すように設定
(defun markdown-custom ()
  "markdown-mode-hook"
  (setq markdown-command-needs-filename t)
  )
(add-hook 'markdown-mode-hook '(lambda() (markdown-custom)))

最後に

今までMarkdownをEmacsで書いてるけど、プレビューはできていなかったので、かなり改善しました。 今回はPythonのGripを例にしましたが、markdownというShellスクリプトでラップしてあげればどんな変換ツールでも動きます。 (markdownというコマンド名もmarkdown-commandをカスタマイズすれば好きなのにできます)

補足

本来、Gripも標準入力・標準出力をサポートしているのでmarkdown-commandを"grip --export -"に設定すれば、/usr/local/bin/markdownでラップしてあげなくてもよいはず。

しかし、日本語で書かれたREADME.mdに対して、以下のコマンドを実行すると、文字コード周りのエラー出てしまう。

cat README.md | grip --export - | less

なので、ラップしてファイル名を受け取ってHTMLを出力するのが今のところ安定している。

Squid調査

Squidというプロキシサーバーを使ってみました。

アクセスログの設定で調べたことをまとめて置きます。

インストール方法

MacにHomebrewでインストールしました

$ brew install squid

squidのバージョンは

$ squid -v
Squid Cache: Version 3.3.11

設定ファイル

Homebrewでインストールした場合、設定ファイルは、 /usr/local/Cellar/squid/3.3.11/etc以下にあります。

基本的な設定はsquid.confで行います。

アクセスログの設定

Squidのバージョンにより設定方法が何度も変わっているようです。 v3.3では次の設定が正しいです。

access_log daemon:/usr/local/var/logs/access.log combined

access_log: アクセスログに関する設定はここに書く

daemon:Squidはv3.2からいろんな方法でログを出力できるようになりました。どの方法(どのモジュールを使って)ログを出力するのかを指定します。

昔は直接ファイルに書き込んでいて、I/Oオーバーヘッドが大きかった ファイルに出力するならより高速なdaemonモジュールがおすすめ。

stdio module to send log data directly from Squid to a disk file. This is the historic behaviour of Squid before logging modules were introduced, and remains the default used when no module is selected. It is recommended to upgrade logging to the faster daemon: module.

source: http://www.squid-cache.org/Doc/config/access_log/

/usr/local/var/logs/access.log:アクセスログの出力先を指定する。Homebrewで入れたSquidaccess_logディレクティブで何も設定しないと、ここに出力していたので同じ場所を指定。

combined:ログのフォーマットを指定する。ログのフォーマットは自分でも定義できる。標準で使えるのは、以下の5つ

  • squid: Squid独自のログ(キャッシュ情報とかに特化?)
  • common:CLF形式
  • referrer:基本的にReferrerのみ
  • useragent:基本的にUser Agentのみ
  • combined:CLF形式にreferrerとuseragentの情報を合体させたもの

参考: http://www.squid-cache.org/Doc/config/logformat/

ログ形式の設定

標準で用意されているログ形式以外に自分で定義することもできる。

http://www.squid-cache.org/Doc/config/logformat/

参考サイト

iOSアプリでやさしさゴシックを使う

アプリを作っていると、iOSで標準で使えるフォントだけではどうもしっくりこない場面が出てきます。

ググってみるとiOS3.2以降、カスタムフォントがサポートされたようで、アプリのリソースにttfファイルやotfファイルを追加して、
Supporting Files>MyAppName-Info.plistに"Fonts provided by application" -> ["fontname.ttf"]っていう関係を作れば、
"fontname"で参照できることがわかりました。

ここらへんは調べるとスクリーンショット付きの解説ブログがたくさんヒットします。(iOSアプリに独自フォントを組み込んで表示する | calmscape: //ソフトウェア開発部)

このブログの通りにしたらIPAフォントはうまく使うことが出来ました。

やさしさゴシックを同じ手順で使おうとしたら、fontnameってどれ?ってなって時間がかかりました。

アプリで参照するときは、
ファイル名から.ttfをとった"07やさしさゴシック"でも、
README内で使われていた"07 YasashisaGothic"でもなく、
"07YasashisaGothic"です!!

よくよくダウンロードしたやさしさゴシックのフォルダ構成を見ると、
その他/unix/07YasashisaGothic.ttfというファイルがあり、この名前を使えばいいってわかりました。

ちなみに、XCodeのリソースに追加するフォントファイルは、07やさしさゴシック.ttfでもOKです(でもunix以下にあったやつ使うけど)

まとめると調べてみつかる手順でフォントファイルの追加とInfo.plistの編集を行って、
参照するときは、こんな感じで書けばいい。

SKLabelNode *myLabel = [SKLabelNode labelNodeWithFontNamed:@"07YasashisaGothic"];

ビリヤードシミュレーションぽいものを作る

その1 誰もがやりたいパーティクルの衝突
その9 移動する2つの球の衝突場所と時刻を得る
楽しい!クリエイト作品!: ビリヤード球の衝突の計算


JavaScript ゲームのための単純な 2D 物理エンジンを作成する


反発係数について
5.2.3.2 2物体の反発係数 ■わかりやすい高校物理の部屋■
ビリヤードの場合e=2

摩擦について
http://www.wakariyasui.sakura.ne.jp/3-3-0-0/3-3-2-4masaturyokuwoukeru.html

忘れていたベクトル
http://homepage2.nifty.com/skimp-studio/htm/crawl/1_2_vector2.htm
ベクトルの内積とは - 大人になってからの再学習


算術関数を使う(Mathクラス) - Javaちょこっとリファレンス

AndroidでOpenGL ES 2.0調査

現在、Androidで何かアプリを作ろうと思い、OpenGL周りを調査しています。

OpenGLで調べるとC++だったり、OpenGL 1.0, 1.1だったり、
OpenGL 2.0の
意外とWeb上に完全な情報がまとまっておらず線を引くだけでも、苦労しました。

(最初に)OpenGL 1.0について

OpenGL ES 2.0の情報になかなかありつけなかったため、OpenGL ES 1.0で実装しようと思いましたが、新しいAPIでは2.0を推奨しているようです。

The example code in this class uses the OpenGL ES 2.0 APIs, which is the recommended API version to use with current Android devices.

また、記憶が曖昧ですが、1.0だと自分のエミュレータでうまく動かず、なんだかんだ頑張って2.0で実装する事にしました。


参考にしたWebサイト

1. Displaying Graphics with OpenGL ES | Android Developers
Androidの公式チュートリアル

基本的には、このWebサイトのOpenGLの項目を順番に読んでいけばいいんだけど、
未定義なローカル変数やメンバ変数を参照していて、どんな値を設定すればいいかわからないという状態になります。


2. Displaying Graphics with OpenGL ES | Android Developers
先ほどのチュートリアルの最終結果の実際に動くコードを載せてくれているブログ

公式チュートリアルが、マジックナンバーを使っている部分も定数としてわかりやすくなっているので、理解が深まります。
また、未定義な変数にどんな値を設定すればいいかもわかると思います。

3. 4. OpenGL Primitives - Square (Version 2.0) – Swiftless Tutorials - OpenGL Tutorials
このサイトはOpenGLで線を引く方法がわからなかった時に、GLES20.GL_LINE_STRIPとかの違いを理解するのに役立ちました。

GL_LINESとGL_LINE_LOOP, GL_LINE_STRIPの違いを図示してくれてるサイト


4. OpenGL ES | Android Developers
OpenGLのことがおおまかに書いてあります。自分は最初にこのサイトに辿り着いたのですが、このサイトだけだと理解出来なかった。
1.のサイトを合わせて読んでようやく具体例がわかった。


5. Android OpenGL ES 2, Drawing squares - Stack Overflow
OpenGLでは四角形を描画する命令はなくて、三角形を描画する命令で描画する。
1. のサイトでも三角形を2つで四角形を描画するSquareクラスを追加しているけど、
肝心のGLES20.glDrawArrays()をどう変えればいいかが載っていない。

また、1.のサイトでは頂点を3×2の6個保持するのは、効率が悪いので、4個保持しておき、描画する順番を別途指定する効率化を行っているけど、その場合glDrawArrays()ではなくて、どうやら GLES20.glDrawElements()を使うようだ。

このAnswerAndroid OpenGL ES 2, Drawing squares - Stack Overflowを読むと、そこら辺のこともわかる。

Tipsになりそうなこと

  • Activityのタッチイベントで取得したx,yはOpenGLのx,yにそのままは使えない
        @Override
        public boolean onTouchEvent(MotionEvent e) {
            // タッチイベントで取得できるx, y
            float x = e.getX();
            float y = e.getY();
            int width = getWidth();
            int height = getHeight();
            
            // OpenGLは中心が(0, 0)
            float centerX = width / 2;
            float centerY = height / 2;
            float glX = (centerX - x) / centerX;
            float glY = (centerY - y) / centerY;
            
            // OpenGLは描画範囲を正方形として扱っており、
            // Rendererクラスでデバイスのアスペクト比に
           // 合わせるように行列演算をしているので
           // それに対応する(glYはそのままの値を使う!)
            glX /= (float)height / width;

            //  ↓適宜描画処理を記述↓
        }
  • 配列を何回も初期化するのを避けるために、2次元の描画に特化したfloat[]のラッパークラスを作った
package com.github.cloverrose.mag;

import java.util.Arrays;

public class FastArray {
    public float[] data;
    public int length;

    private int allocateSize;
    private int lastIndex;
    private int threshold; // use this variable to avoid calculate allocateSize - 1
    
    private static final int INITIAL_SIZE = 5;
    public FastArray(){
        data = new float[3 * INITIAL_SIZE];
        allocateSize = data.length;
        threshold = allocateSize - 1;
        lastIndex = -1;
        length = 0;
    }
    
    
    public FastArray(FastArray src){
        this.data = Arrays.copyOf(src.data, src.data.length);
        this.length = src.length;
        this.allocateSize = src.allocateSize;
        this.threshold = src.threshold;
        this.lastIndex = src.lastIndex;
    }
    
    
    public void append(float x, float y){
        if(lastIndex == threshold){
            data = Arrays.copyOf(data, allocateSize * 2);
            allocateSize = data.length;
            threshold = allocateSize - 1;
        }
        data[++lastIndex] = x;
        data[++lastIndex] = y;
        data[++lastIndex] = 0.0f;
        length += 3;
    }
}


いちいちクラス定義せずに、List使えばいいじゃんって思うけど、

List<Float>.toArray()

だとFloatBuffer.put()の引数に使えない。

疑問点とか

  • タッチで線を描く場合、今までの点を全て配列に保存する?
  • それとも画面をクリアせずに、最新の線だけを描画する?
  • (ちなみに)毎回全ての線を描画しなおしても動作速度は今のところ問題なく速い
  • 最新の線だけを描画する場合、画面の回転とかには対応できなさそう
  • 一定以上線が増えたらBitmap画像にして、直近N個の点だけを配列に保存ということを既存アプリはやってるのかな?
  • デバイスの回転に対応するのが難しい
  • デバイスを回転するとActivityも再度作成されるので、点の配列などが消えてしまう
  • そこでApplicationクラスを継承し、配列をフィールドに持つクラスを使うことで対応
  • しかし、デバイスを回転するとエラーが発生して落ちてしまった