MacPorts で virutalenv, virtualenvwrapper を導入

明日の Python 東海のハンズオンの準備のため,MacPorts で virtualenv, virutalwrapper を導入した.

http://groups.google.com/group/python-tokai/web/12


とりあえず port install

% sudo port install virutalenv-2.6
% sudo port install virutalenvwrapper-2.6
% ln -s /opt/local/Library/Frameworks/Python.framework/Versions/2.6/bin/virtualenv /opt/local/bin/virtualenv
% ln -s /opt/local/Library/Frameworks/Python.framework/Versions/2.6/bin/virtualenvwrapper_bash /opt/local/bin/virtualenvwrapper_bash

virtualenvwrapper が virtualenv という名前のコマンドを要求するため,シンボリックリンクをつくる.
virutalenv-2.6 を入れるだけだと,/opt/local/bin/virutalenv-2.6 がつくられるだけみたい.
ついでに virtualenvwrapper_bash のシンボリックリンクもつくっておいた.


次に仮想環境を入れておくディレクトリをつくる.

% mkdir ~/.virtualenvs


最後に .zshrc なり .bashrc に以下のように追加.

## Python
# virtualenv
export WORKON_HOME=${HOME}/.virtualenvs
if VIRTUALENVWRAPPER=`which virtualenvwrapper_bashrc` ; then
	source ${VIRTUALENVWRAPPER}
fi

virtualenv の使い方は他のサイトにいっぱい載ってるのでそちらで.

名古屋 Hackathon ラムダ村 に参加してきました

もう一週間以上も経ちますが,名古屋 Hackathon に参加してきました.

主催者の @ さんをはじめ他の参加者のみなさんのおかげでとても楽しい時間をすごせたことを感謝いたします.

さて,自分は @ さん,@ さん,@ さんとともに Python 組で参加してきました.

やろうとしたこと

Python 組では Python 3.1 を使って twitter クライアントの作成に挑戦しました.

Python 3.1 には,twitter ライブラリも OAuth ライブラリもないようなので,そこから作成しました.

はまったこと

Python 3.1 でやってく上ではまったことは,strbytes の扱いです.

OAuth では HMAC や base64 を使うのですが,Python 2 と Python 3 とでは引数や返り値が違うという問題にはまりました.

Python 3 では strUnicode 文字列になってかなりハッピーなのですが,bytes が関係するところではかえって面倒なことになってます.

できたこと

結局,OAuth でアクセス トークンを取得するところまでしかできませんでした.

成果物は https://bitbucket.org/kei10in/pytter/:title= にあるので興味のある方はご覧ください.

今もちょいちょい触ってます.

その後

名古屋 Hackathon 後 @ さんが https://bitbucket.org/terurou/oauth-python3:title= に update と home_timeline ができるものを公開してくださっています.

感想

はじめての Hackathon への参加ですがとても楽しい時間を過ごすことができました.

せっかく多くの技術者が集まっているので,次回があればコード レビューとかもやってみたいです.

設定ファイルを bitbucket で管理する

いつかやろう,やろうと思ってた設定ファイルの Web 上での管理をやってみました.

いろいろな環境で同じ設定を使ったり,バックアップのやり忘れをさけたいといった場合は Web 上での管理がいいと思います.


管理には bitbucket を使うことにしました.

Python が好きなので.


そして,Mercurial デビューです (*'ω')b

手順


まず,bitbucket のアカウントがないと始まらないので取得します.

次に,[Repositories] から [Create new repository] を選択してリポジトリを作ります.


bitbucket にリポジトリを作ったら,ローカルに作業ディレクトリを作ります.

ここに設定ファイルをおくことになります.

% mkdir path/to/working/directory
% cd path/to/working/directory


bitbucket のリポジトリから clone をして作業ディレクトリにローカル リポジトリを作ります.

% hg clone https://{USER_NAME}@bitbucket.org/{USER_NAME}/{REPOSITORY_NAME}
% cd {REPOSITORY_NAME}


ローカル リポジトリのディレクトリに bitbucket で管理したい設定ファイルをコピーします.

% cp -rf ~/.emacs.d emacs.d
% cp ~/.zshrc zshrc
などなどをコピーする.

.elc とか管理したくないファイルは .hgignore というファイルをリポジトリのルートにおいて,その中にいろいろ記述するといいです.

ちなみに今回自分が作ったのはこんな感じです.

syntax: glob
*~
*.elc
*.pyc
.DS_Store
Thumbs.db
ac-comphist.dat
auto-save-list


リポジトリのディレクトリにコピーしたファイルを add して,commit して push します.

% hg add *
% hg commit -m
% hg push https://{USER_NAME}@bitbucket.org/{USER_NAME}/{REPOSITORY_NAME}


最後に,ローカル リポジトリのファイルのシンボリック リンクをホームディレクトリに作ります.

% ln -s emacs.d ~/.emacs.d
% ln -s zshrc ~/.zshrc

参考サイト

今回参考にしたところを紹介しておきます.


それと自分の設定ファイルも

可読性について

まずは、" プログラムの可読性に関する検討 - Life like a clown" をご覧ください。


で、サンプルのプログラムについて、自分としては [5] はなしかなと。

理由は、a ≠ b の評価値と関数 f の引数が bool であることに因果関係を見出せないから。

たとえば f に渡す引数が true, false でなくて、1, 2 とかだったら [5] は使えない。


ところで、ここで話題にしてるのは可読性について。

可読性をあげるには一貫性が必要なのだと思うのだけど、[5] は「f の引数が bool のときにのみ限定的に記述できる方法」でしかないと思うんです。

つまり、[5] だと一貫性を保つことが難しいため、なしと思います。

TDD Boot Camp 名古屋 1 日目でやったことを Python で復習する その 2

今日は TDD Boot Camp 名古屋 1 日目のペアプロ体験の後半でやった仕様変更の復習をするよ!

前回のものに仕様変更を加えていく.

仕様変更 1

一度にいっぱい set できる set_multi と一度にいっぱい get できる get_multi を実装する仕様変更.

正確仕様はちょっとうろ覚えだけど,だいたいこんな感じの仕様.

>>> store = FileStore()
>>> store.set_multi({'foo': 'hoge', '': 'toto', 'bar': 'fuga'})
>>> store.dump()
'foo:hoge\nbar:'fuga\n'
>>> store.get_multi(['bar', 'foo', None])
['fuga', 'foo']
まず set_multi のテストから
class TestFileStore(unittest.TestCase):

    def setUp(self):
        self.store = FileStore()
        self.store.set('foo', 'hoge')

    def test_set_multi(self):
        self.assertEqual(self.sotre.dump(),
                         'foo:hoge\nbar:fuga\nbuzz:piyo\n')

assert から書くのを忘れない(*'ω')b

次に,この assert が成功する用に set_multi する.

class TestFileStore(unittest.TestCase):

    def setUp(self):
        self.store = FileStore()
        self.store.set('foo', 'hoge')

    def test_set_multi(self):
        self.store.set_multi({'bar': 'fuga', 'buzz':'piyo'})
        self.assertEqual(self.store.dump(),
                         'foo:hoge\nbar:fuga\nbuzz:piyo\n')

ここまでできたら set_multi を実装する.

set_multi の実装

テストができたから set_multi を実装する.

明白な実装なのでそのまま実装しちゃう.

実装はこんな感じ

class FileStore(object):

    def __init__(self):
        self._store = OrderedDict()

    def set(self, key, value):
        if key is None or key is '':
            return
        if key in self._store:
            self._store.pop(key)
        self._store[key] = value

    def set_multi(self, pairs):
        for k, v in pairs.items():
            self.set(k, v)

    ...

テストもばっちり成功!!

get_multi のテストと実装

set_multi と同様に get_multi も行います.

1. テスト作成
2. テスト失敗
3. 実装
4. テスト成功

は変わりません.

うんで,出来上がるテストと実装はこんな感じ.

class FileStore(object):

    ...

    def get(self, key):
        return self._store.get(key, None)

    def get_multi(self, keys):
        return [self.get(k) for k in keys if k in self._store]
        
    ...


import unittest

class TestFileStore(unittest.TestCase):

    def setUp(self):
        self.store = FileStore()
        self.store.set('foo', 'hoge')

    ...

    def test_get_multi(self):
        self.store.set_multi({'bar': 'fuga', 'buzz':'piyo'})
        self.assertEqual(
            self.store.get_multi(['buzz', 'toto', '', 'bar']),
            ['piyo', 'fuga'])

set_multiget_multi も既存のメソッドに影響を与えないので,わりと簡単に追加できた.

次の仕様変更はちょっと大変だよ!

仕様変更 2

メインディッシュきた!

次の仕様変更はこんな感じ.

>>> store = FileStore()
>>> store.set('foo', '${now}') # 現在時刻が登録される
>>> store.get('foo')
2010-07-16T21:57:48
テストがかけない.

残念ながらこのままじゃテストを書けない (>_<)

現在時刻とかをテストで扱うのはぶっちゃけ無理.

テストが書けない場合,テストができない原因になっているところだけ取り出して,それ以外のところでテストすればいいと思う.

なので開き直って現在時刻をテストするのはしない.

ここではテストするのは set が "${now}" を何かしら展開しよするかどうかをテストする.

そんなテストはこんな感じに書いた.

class FakeExpander(object):
    def expand(self, value):
        if value == '${now}':
            return '%s is expanded' % value
        return value


class TestFileStore(unittest.TestCase):

    def setUp(self):
        self.store = FileStore()
        self.store.set('foo', 'hoge')

    def test_set(self):
        fake_expander = FakeExpander()
        self.store.set_expander(self.fake_expander)
        self.store.set('bar', '${now}')
        self.assertEqual(self.store.dump(), 'foo:hoge\nbar:${now} is expanded\n')

    ...

このテストがクリアされるように set を修正し,こっそり増えた set_expander を追加する.

class Expander(object):
    def expand(self, value):
        if value == '${now}':
            return datetime.now().strftime('%Y-%m-%d %H:%M:%S')
        return value

class FileStore(object):

    def __init__(self):
        self._store = OrderedDict()
        self._expander = Expander()

    def set_expander(self, expander):
        self._expander = expander

    def expand(self, value):
        return self._expander.expand(value)

    def set(self, key, value):
        if key is None or key is '':
            return
        if key in self._store:
            self._store.pop(key)
        self._store[key] = self.expand(value)

    ...

さらにこっそり,expand も追加されてるけど気にしない.
というのも set_expander にしろ,expand にしろそこに不安はないのでテストはない.

もう一点,Expander っていうクラスを追加した.

ここがまさにテストの出来ない部分で,ここについてのテストは書かないことにした.

テストが出来ない部分はテストが必要ないくらい単純なものにしてやれば,開き直ってテストなしでいいと思う.


さらに Expander クラスを導入したことで,"${now}" 以外に "${name}" とか増やしたくなった場合でも,FileStore にテストを追加する必要はなくて,Expander の方をごにょごにょしてやればよくなってます.

まとめ

TDD Boot Camp 名古屋の 1 日目でやったことの復習をした.

とりあえず,仕様変更 2 までやった.

仕様変更 3 (データの生存期間指定機能の追加) は力尽きたので省略しちゃう (ごめんなさい (>_<) )

仕様変更 3 も仕様変更 2 のときと同じように,テストができない部分は最小化してモックオブジェクトとか作ってテストすればいいと思う.

仕様変更 3 の場合だったら,CachedFileStore クラスを導入してデータの保持とかは FileStore に委譲.
CachedFileStore はデータの生存,消滅の管理やらせて,消滅させるかどうかの判断だけを行うクラスを導入.

仕様変更 3 でテストできないのが時間関連の判断だけなので,そこをちっちゃいクラスに閉じ込めてしまえば他の部分は全部テストできるようになるっていう思惑.

責任の分割,超大切.


TDD では,とにかくテストから書く.

テストの中では assert から書く.

普通のプログラムはメソッドの上から書くけど,テスト プログラムはメソッドの下から書く.

テストもメンテナンスする.


最期に最終的なコードを.

#!/usr/bin/env python3
# -*- utf-8 -*-

from datetime import datetime
from collections import OrderedDict

class Expander(object):
    def expand(self, value):
        if value == '${now}':
            return datetime.now().strftime('%Y-%m-%d %H:%M:%S')
        return value

    
class FileStore(object):

    def __init__(self):
        self._store = OrderedDict()
        self._expander = Expander()

    def set_expander(self, expander):
        self._expander = expander

    def expand(self, value):
        return self._expander.expand(value)

    def set(self, key, value):
        if key is None or key is '':
            return
        if key in self._store:
            self._store.pop(key)
        self._store[key] = self.expand(value)

    def set_multi(self, pairs):
        for k, v in pairs.items():
            self.set(k, v)

    def get(self, key):
        return self._store.get(key, None)

    def get_multi(self, keys):
        return [self.get(k) for k in keys if k in self._store]
        
    def dump(self):
        return '\n'.join(
            [':'.join([k, v]) for k, v in self._store.items()]) + '\n'



import unittest


class FakeExpander(object):
    def expand(self, value):
        if value == '${now}':
            return '%s is expanded' % value
        return value


class TestFileStore(unittest.TestCase):

    def setUp(self):
        self.store = FileStore()
        self.store.set('foo', 'hoge')

    def test_set(self):
        fake_expander = FakeExpander()
        self.store.set_expander(fake_expander)
        self.store.set('bar', '${now}')
        self.assertEqual(self.store.dump(),
                         'foo:hoge\nbar:${now} is expanded\n')

    def test_get1(self):
        self.assertEqual(self.store.get('foo'), 'hoge')

    def test_get_miss_hit(self):
        self.assertEqual(self.store.get('toto'), None)

    def test_set_invalid_key1(self):
        self.store.set('bar', 'fuga')
        self.store.set(None, 'momo')
        self.assertEqual(self.store.dump(), 'foo:hoge\nbar:fuga\n')

    def test_set_invalid_key2(self):
        self.store.set('bar', 'fuga')
        self.store.set('', 'momo')
        self.assertEqual(self.store.dump(), 'foo:hoge\nbar:fuga\n')

    def test_set_overwrite(self):
        self.store.set('bar', 'fuga')
        self.store.set('foo', 'buzz')
        self.assertEqual(self.store.dump(), 'bar:fuga\nfoo:buzz\n')

    def test_dump1(self):
        self.assertEqual(self.store.dump(), 'foo:hoge\n')

    def test_dump3(self):
        self.store.set('bar', 'fuga')
        self.assertEqual(self.store.dump(), 'foo:hoge\nbar:fuga\n')
        
    def test_set_multi(self):
        self.store.set_multi({'bar': 'fuga', 'buzz':'piyo'})
        self.assertEqual(self.store.dump(),
                         'foo:hoge\nbar:fuga\nbuzz:piyo\n')

    def test_get_multi(self):
        self.store.set_multi({'bar': 'fuga', 'buzz':'piyo'})
        self.assertEqual(
            self.store.get_multi(['buzz', 'toto', '', 'bar']),
            ['piyo', 'fuga'])


if __name__ == '__main__':
    unittest.main()

TDD Boot Camp 名古屋 1 日目でやったことを Python で復習する

タイトルとおりです.

id:t-wada さんからも許可得ることができたのでお題も Python で書き直してみます.


あ,ちなみに Python 3.1 です.

お題

↓のような仕様の FileStore クラスを作ります.

>>> store = FileStore()
>>> sotre.set('foo', 'hoge')
>>> store.get('foo')
'hoge'
>>> store.dump()
'foo:hoge\n'
>>> store.set('bar', 'fuga')
>>> store.dump()
'foo:hoge\nbar:fuga\n'
>>> store.get('toto')
None
>>> store.set(None, 'momo')
>>> store.dump()
'foo:hoge\nbar:fuga\n'
>>> store.set('foo', 'piyo');
>>> store.dump()
'bar:fuga\nfoo:piyo\n'

まずはテストから書く

get のテスト書く.

assert first

テストを書くときは assert から書く.

import unittest

class TestFileStore(unittest.TestCase):

    def test_get1(self):
        self.assertEqual(store.get('foo'), 'hoge')


if __name__ == '__main__':
    unittest.main()

こんな感じ.

でもこれを実行するとエラーになっちゃう.

% FileStore.py
E
======================================================================
ERROR: test_get1 (__main__.TestFileStore)
----------------------------------------------------------------------
Traceback (most recent call last):
  File "FileStore.py", line 10, in test_get1
    self.assertEqual(store.get('foo'), 'hoge')
NameError: global name 'store' is not defined

----------------------------------------------------------------------
Ran 1 test in 0.000s

FAILED (errors=1)

とりあえずエラーにならないところまで書く.

それと,そもそも set して get すると値が得られるという仕様のはずなので set も追加する.

#!/usr/bin/env python3
# -*- utf-8 -*-

class FileStore(object):

    def set(self, key, value):
        pass

    def get(self, key):
        pass


import unittest

class TestFileStore(unittest.TestCase):

    def test_get1(self):
        store = FileStore()
        store.set('foo', 'hoge')
        self.assertEqual(store.get('foo'), 'hoge')


if __name__ == '__main__':
    unittest.main()

これで Error じゃなくて Fail になったはず.

% FileStore.py
F
======================================================================
FAIL: test_get1 (__main__.TestFileStore)
----------------------------------------------------------------------
Traceback (most recent call last):
  File "FileStore.py", line 21, in test_get1
    self.assertEqual(store.get('foo'), 'hoge')
AssertionError: None != 'hoge'

----------------------------------------------------------------------
Ran 1 test in 0.000s

よし,おk.

仮実装 (Fake it)

Fake itはテストのテスト

TDD Boot Camp 名古屋に登壇させていただきました - t-wadaの日記

ということでまずgetを仮実装する.

class FileStore(object):

    def set(self, key, value):
        pass

    def get(self, key):
        return 'hoge'

そしてテスト.

% FileStore.py
.
----------------------------------------------------------------------
Ran 1 test in 0.000s

OK

やったー.「OK」だってーーー!!!

三角測量 (Triangulation)

さぁ,仮実装をいじめるぞ!!

class TestFileStore(unittest.TestCase):

    def test_get1(self):
        store = FileStore()
        store.set('foo', 'hoge')
        self.assertEqual(store.get('foo'), 'hoge')

    def test_get2(self):
        store = FileStore()
        store.set('bar', 'fuga')
        self.assertEqual(store.get('bar'), 'fuga')

ぎゃ!仮実装じゃこんなテストを追加されたらひとたまりもない.

ということでset, getを実装します.

#!/usr/bin/env python3
# -*- utf-8 -*-

from collections import OrderedDict

class FileStore(object):

    def __init__(self):
        self._store = OrderedDict()

    def set(self, key, value):
        self._store[key] = value
    
    def get(self, key):
        return self._store[key]


import unittest

class TestFileStore(unittest.TestCase):

    def test_get1(self):
        store = FileStore()
        store.set('foo', 'hoge')
        self.assertEqual(store.get('foo'), 'hoge')

    def test_get2(self):
        store = FileStore()
        store.set('bar', 'fuga')
        self.assertEqual(store.get('bar'), 'fuga')
        
if __name__ == '__main__':
    unittest.main()
% FileStore.py
..
----------------------------------------------------------------------
Ran 2 tests in 0.000s

OK

(*'ω')b

ここでは,dump で順番の保持が必要そうなので collections.OrderedDict 使ったよ.

テスト->実装->リファクタリング

この調子で dump とか get,set の細かい仕様を実装していく

まずdump
class FileStore(object):

    ...

    def dump(self):
        return '\n'.join(
            [':'.join([k, v]) for k, v in self._store.items()]) + '\n'


import unittest

class TestFileStore(unittest.TestCase):

    def test_get1(self):
        store = FileStore()
        store.set('foo', 'hoge')
        self.assertEqual(store.get('foo'), 'hoge')
        
    def test_get2(self):
        store = FileStore()
        store.set('bar', 'fuga')
        self.assertEqual(store.get('bar'), 'fuga')

    def test_dump1(self):
        store = FileStore()
        store.set('foo', 'hoge')
        self.assertEqual(store.dump(), 'foo:hoge\n')

    def test_dump2(self):
        store = FileStore()
        store.set('bar', 'fuga')
        self.assertEqual(store.dump(), 'bar:fuga\n')

    def test_dump3(self):
        store = FileStore()
        store.set('foo', 'hoge')
        store.set('bar', 'fuga')
        self.assertEqual(store.dump(), 'foo:hoge\nbar:fuga\n')
  1. テスト test_dump1 を作成
  2. テスト実行: 失敗
  3. FileStore.dump を仮実装
  4. テスト実行: 成功
  5. テスト test_dump2 を作成
  6. テスト実行: 失敗
  7. FileStore.dump を実装
  8. テスト実行: 成功
  9. テスト test_dump3 を作成
  10. テスト実行: 成功

っていう流れ.

テストのリファクタリング

いい加減 store = FileStore() とか store.set('foo', 'hoge') って書くのがだるいのでテストをリファクタリングする.ついでに test_get2, test_dump2 ももういらないので削除する.

で,こうなる

class TestFileStore(unittest.TestCase):

    def setUp(self):
        self.store = FileStore()
        self.store.set('foo', 'hoge')

    def test_get1(self):
        self.assertEqual(self.store.get('foo'), 'hoge')
        
    def test_dump1(self):
        self.assertEqual(self.store.dump(), 'foo:hoge\n')

    def test_dump3(self):
        self.store.set('bar', 'fuga')
        self.assertEqual(self.store.dump(), 'foo:hoge\nbar:fuga\n')
細かい仕様を実装

とりあえずは最終形.

#!/usr/bin/env python3
# -*- utf-8 -*-

from collections import OrderedDict

class FileStore(object):

    def __init__(self):
        self._store = OrderedDict()

    def set(self, key, value):
        if key is None or key is '':
            return
        if key in self._store:
            self._store.pop(key)
        self._store[key] = value

    def get(self, key):
        return self._store.get(key, None)

    def dump(self):
        return '\n'.join(
            [':'.join([k, v]) for k, v in self._store.items()]) + '\n'


import unittest

class TestFileStore(unittest.TestCase):

    def setUp(self):
        self.store = FileStore()
        self.store.set('foo', 'hoge')

    def test_get1(self):
        self.assertEqual(self.store.get('foo'), 'hoge')

    def test_get_miss_hit(self):
        self.assertEqual(self.store.get('toto'), None)

    def test_set_invalid_key1(self):
        self.store.set('bar', 'fuga')
        self.store.set(None, 'momo')
        self.assertEqual(self.store.dump(), 'foo:hoge\nbar:fuga\n')

    def test_set_invalid_key2(self):
        self.store.set('bar', 'fuga')
        self.store.set('', 'momo')
        self.assertEqual(self.store.dump(), 'foo:hoge\nbar:fuga\n')

    def test_set_overwrite(self):
        self.store.set('bar', 'fuga')
        self.store.set('foo', 'buzz')
        self.assertEqual(self.store.dump(), 'bar:fuga\nfoo:buzz\n')

    def test_dump1(self):
        self.assertEqual(self.store.dump(), 'foo:hoge\n')

    def test_dump3(self):
        self.store.set('bar', 'fuga')
        self.assertEqual(self.store.dump(), 'foo:hoge\nbar:fuga\n')
        

if __name__ == '__main__':
    unittest.main()

やっぱり,ここでも

  1. テスト作成
  2. テスト実行: 失敗
  3. 実装
  4. テスト実行: 成功

の流れには逆らわずにひたすらまわす.

とりあえず

基本仕様の実装ができました.

明日はこれに,TDD Boot Camp でもやった仕様変更を追加していきたい.


今日は眠いのでおしまい!!

TDD Boot Camp 名古屋に参加してきた

2010年7月10日から11日まで2日間に渡ってTDD Boot Camp 名古屋に参加してきた.

id:t-wada さん,id:bleis-tiftさん,他すべてのみなさんありがとございました.
とても楽しく参加することができました.


どんな内容だったかは,TDD Boot Camp名古屋 - 名古屋アジャイル勉強会 - Yahoo!ブログトラックバックにみなさんがすでに書いておられるので,ここでは TDDBC で行ったペアプログラミングとTDD道場の感想を書きます.

ちなみに,ペアプログラミングと道場は言語ごとに分かれてやってます.
自分は C++ での参加です.

1 日目 ペアプログラミング

内容: TDD 体験ペアプログラミング

ペアプログラミング初体験.

人のプログラミングの流れを見るのも初めてだし,人に見せるのも初めて.

ペアプロを仕事でやるにはまだちょっと不安があるけど,一生で一度は絶対にやるべきと思う.
単純に参考になることいっぱいあるし,相手に教えることもできて楽しい.

2 日目 TDD道場

内容: レガシコード改善 TDD 道場

道場初体験.

目標大事

最初に目標をどうするかをしっかり決めたグループもあるくらい.

特に比較的多めの人数で行うため,目標が定まってないとメンバーがそれぞれ違う方向を向いてしまうこともある.


そもそもレガシーコードに立ち向かうときには仕様変更とかバグフィックスのような目標があるはず.

そういった目標がない限りはレガシーコードを改善する必要はないはず.

そういう意味でも目標設定が大事だなと痛感した.

宗教戦争

ペアプログラミングとは宗教戦争の始まりのこと(うそ)

まずは自分の宗教および宗派から

OS: Mac
エディタ: Emacs
キーボード: 英語配列

まずは OS

さて,会場の半分くらいはMac.

世間とはかけ離れた環境ですね!!ヽ(´ー`)ノ

あとたぶんWindowsノートの格好をしたLinuxとかBSDとかSolarisもいるはず!!

なのできっと Mac > Win > Linux


自分が参加するC++では???

Win: 4人, Linux: 1人,Mac: 1人 (自分)

惨敗ですがな、、、

だいたい予想はしてたけどね.

エディタとかIDEとか

Emacsな人もvimな人もeclipseな人もおんなじくらいいる感じ

Javaの人はみんなeclipseだったみたいです.

NetBeansRubyで使ってるのみた.

キーボード

英語配列の人はざっと見た感じで自分以外に2, 3人しかいなさそう.

英語配列の人ってやっぱり少ないのかなぁ.

「俺,英語配列だよ!!」っていう人いないかな.

戦い

みんな大人なのでみにくいあらそいはありませんでした.

ざんねん☆