英語弱者のためのchromeプラグイン

python界の英弱、feizです。

英語の文章を読む時に便利なchromeの辞書/翻訳プラグインを2つ紹介します。英弱必携。

英辞郎

英辞郎 on the WEB 拡張機能 - Chrome Web Store

ページ内の単語選択>右クリックメニュー>英辞郎で検索 で英辞郎 on the webの検索結果が別タブで開く

単語の意味を正確に調べるなら英辞郎が最強だと思う。

MultiLookup

MultiLookup - Chrome Web Store

初期設定としてオプションページのサイト選択の右側からgoogle翻訳(英日)を選んで右側に移してチェックを入れる。

ページ内の翻訳したい文章選択>右クリックメニュー>MultiLookup->自動判別 でページ下部にオーバーレイで原文と翻訳結果が出てくる。

オーバーレイで ってとこがかなり素敵。わかんないとこだけ大雑把に訳してざくざく読み進めるのに非常に便利。

おしまい

どちらも翻訳結果見るまでのアクションが少なくていい。こういうツールは本来やりたいことの邪魔をしないことが重要だ。

form.clean_xxxの実行順

重要な追記

コメ欄でぼこすか殴られたので追記。
こういう複数のフィールドにまたがるバリデーションはcleanを使うべきで、↓みたいなコードを書くべきではありません。
この記事の趣旨は今まで不定だと思いこんでたclean_xxxの実行順が実は決まってたというのと、それを悪用するとこんなカウボーイコードもかけちゃうみたいな話でした。

http://docs.djangoproject.com/en/dev//ref/forms/validation/

djangoのフォームはclean_[FIELD NAME]というメソッドを生やすと独自のバリデーションを定義できます。

これを(無理やり)使ってパスワード確認入力の一致チェックをやろうとすると

class PasswordForm(forms.Form):
    password = forms.CharField(label=u"パスワード")
    password2 = forms.CharField(label=u"確認入力")

    def clean_password2(self):
        if self.cleaned_data['password'] != self.cleaned_data['password2']:
            raise forms.ValidationError(u"一致しません")

みたいになりますが、clean_password2の実行時点でcleaned_data['password']が存在するかどうかはフォームフィールドの定義順に依存しているので注意が必要です。*1

追ってみる

各cleanの実行順とcleaned_dataの状態をprintデバッグでおっかけると

class DebugField(forms.CharField):
    def clean(self, val):
        print "clean DebugField %s" % val
        return super(DebugField, self).clean(val)

class DebugForm(forms.Form):
    password = DebugField()
    password2 = DebugField()
    
    def clean_password(self):
        print "clean_password"
        print self.cleaned_data
        return self.cleaned_data['password']

    def clean_password2(self):
        print "clean_password2"
        print self.cleaned_data
        return self.cleaned_data['password2']

実行

>>> DebugForm({'password': 'password', 'password2': 'password2'}).is_valid()
clean DebugField password
clean_password
{'password': u'password'}
clean DebugField password2
clean_password2
{'password2': u'password2', 'password': u'password'}
True

とまあ、Field.clean->form.clean_field という1セットをフィールド分繰り返しているのが分かります。

clean_passwordの時点ではcleaned_dataはpasswordのデータしかないので、ここでpassword2を参照しようとしてもだめです。

定義順ってほんと?

これがほんとに定義順になってるのか気になったのでもう少し追ってみた。

django/forms/form.py

    def _clean_fields(self):
        for name, field in self.fields.items():
            ...

items()じゃん。なってねぇくせー

と思ったら

>>> type(DebugForm().fields)
<class 'django.utils.datastructures.SortedDict'>

SortedDictなので順番は持ってるっぽい

def get_declared_fields(bases, attrs, with_base_fields=True):
    ...
    fields = [(field_name, attrs.pop(field_name)) for field_name, obj in attrs.items() if isinstance(obj, Field)]
    fields.sort(key=lambda x: x[1].creation_counter)

Fieldインスタンスのcreation_counterなる値でソートしているらしい

django/forms/fields.py

class Field(object):
    ... 

    # Tracks each time a Field instance is created. Used to retain order.
    creation_counter = 0

    def __init__(self, required=True, widget=None, label=None, initial=None,
                 help_text=None, error_messages=None, show_hidden_initial=False,
                 validators=[], localize=False):
        ...
        # Increase the creation counter, and save our local copy.
        self.creation_counter = Field.creation_counter
        Field.creation_counter += 1

Field.creation_counterという属性値が__init__が呼び出されるたびにカウントアップされて各インスタンスのcreation_counter属性にセットされてるようだ。

これならたしかに定義順=__init__が呼び出される順にソート可能だ。

まとめ

  • clean_xxxメソッド内部で別フィールドのcleaned_dataを参照することはできる
  • ただし自分より前に定義されているフィールドの値しか参照できない
  • そういう処理はcleanメソッドでやれ

*1:ドキュメントでも実行順については少し言及されている

django標準テンプレート構文で文字列の足し算ぽいこと


forloop.counterを使って「お届先住所X」という文字列をテンプレート上で作りたかったのだが、あいにくdjangoテンプレートは簡単には足し算ができるようになっていない。

addフィルタを使えば

"お届け先住所"|add:"いち"

のようなことはできるのだが、"いち"をコンテキスト変数にすることはできない。int値であるforloop.counterにはできない。

追記: 足し算ができないのは文字列と数値の足し算ができないというただそれだけの話でした。コンテキスト変数を渡すことはできます。

そこで

forloop.counter|stringformat:"%お届け先住所%s"|slice:"1:"

こんなことをしてみた。なにやってんのかわからない人はstringformatタグの実装読んでください。

ばかっぽい(´・ω・)


7/50

しごととおかねとエンジニア : 新卒準備カレンダー2011春

新卒準備カレンダー 2011春 : ATNDというイベントに参加させていただきました。

なんかちょっと、偉そげなこととか書いてみたいと思います。

とはいえ、他の方みたく魔法とかシリコンバレーとかかっこいい言葉はでてきません。すいません。

内容

エンジニアという仕事はどういうものか、金を稼ぐというのはどういうことかについて、これまで僕が経験してきたことを元に思うところを書き連ねます。

お前、だれよ

東 健太:@feiz といいます。

87年生まれの23歳、高専出身、こんな歳ですが社会人そろそろ4年目です。

「おめえほんとは0x23歳なんだろ」などとよく言われるおっさん顔です。

新卒ハタチで某携帯電話アプリ屋さんに入社し、ガラケーJavaが致命的に肌に合わず1年半で転職。

現在は株式会社ビープラウドというところで、Python+djangoなwebアプリを書くなどしてほそぼそと生きています。

このイベントの4日目に記事を書いてる@tokibitoとは会社の同僚で、学校の先輩で、弟子みたいな関係です。

好きなひだまりスケッチキャラは宮子、好きなまどマギキャラはマミさんです。

1. しごとについて

なんのために

さて、エンジニアである我々が会社で成すべきことはなんでしょうか?

やっぱりエンジニアですし、最新技術を導入して、イケてる開発プロセスでもって、カッコいいコードを書くことでしょうか?

いいえ、ちがいます。

エンジニアの至上命題は、「様々な問題を技術力などで解決してあげること」です。

技術力を駆使することは、その目的を達成するためのひとつの手段にしか過ぎません。

そこを履き違えて技術に拘泥すると、大抵ロクなことになりません。

最高のものをつくる<>妥協点を模索する

エンジニアのみなさんならよくご存知かと思いますが、いいモノを作るには時間がかかり、新しいことに挑戦するには時間と勉強をする努力が必要です。

そして、趣味のときはほぼ無限だった時間が、仕事ではいろんな条件(予算、納期、リリース日etc)で制約がかけられます。

時には悪態をつきながら非効率な方法で仕事を進める必要があるときもありますし、納得がいかない状態でもリリースしなくてはいけないこともあるでしょう。

そんな情況においては、適切な妥協と取捨選択をし、最終的に仕事を成功に導くのもエンジニアの重要な役目です。

妥協だけじゃ面白くない

かといって、ただ妥協するだけでは前に進みません。つまらない仕事をつまらないまま100万遍繰り返しても、つまらないままです。

ほんの少しずつでも、改善のための仕込みをしておいたり、自分がよいと思う手法を取り入れ、試してみるなどの工夫をすることが大切だと思います。

単なるコーディング能力も大事ですが、こういう仕込みが出来ることもまた重要です。

2. おかねについて

おかねはだいじだ

カネの話に抵抗感があるひともいるかもしれませんが、仕事するということはお金を稼ぐということです。

お金がないとごはんがたべられません。ろくな家に住めません。夏と冬に有明で札ビラをぶちまけて薄い本を買い漁ることもできません。

夢だけで飯は食えないのです。

カネが稼げないとどうなるか

上記のとおり、お金がないと生活に余裕がなくなります。生活に余裕がなくなると、新しい技術を勉強したりする暇もなくなり、停滞の泥沼にはまっていきます。

覚悟を決める 新卒準備カレンダー 2011春 - Doge log でも書かれていますが、エンジニアである限り我々は一生学び続けなくてはなりません。

その学ぶ時間を少しでも多く、継続的に確保し続ける為にも、しっかりと稼がなくてはなりません。

また、当然ですがお金を稼げないと会社が潰れるか、さもなくばクビになってしまいます。大体は後者でしょう。ああおそろしい。

給料

お金といえばやっぱり給料です。会社に入ってから当面の間は、自分のもらう給料が一番意識する「お金」になることでしょう。

さて、この給料というモノは一体なぜ貰えるのでしょうか?

アルバイトであれば、働いた時間*時給で貰えるものだと決まっていますが、正社員に時給なんてものは存在しません。

では給料は何に対して払われているのか。

僕は給料を払う立場になったことはないので不確かかもしれませんが、おおまかに言えばその人が生み出した「価値」に対して払われている という認識をしています。

価値

横文字好きなサラリーマンが「バリュー」とか言ってる奴です。

価値とひとことに言ってもいろいろありますし、人によって解釈も異なると思いますが、いくつか例をあげてみます。

bold;">100万円の受託案件のプログラミングを担当し、成功させた。: 非常に分かりやすいです。大体ひゃくまんえんぐらいの価値がありそうです。
bold;">社内の開発フローを改善し、標準化して普及させた。: 業務効率がアップすることは、大小に関わらず会社全体の役に立つことですので、価値あることでしょう。
bold;">知り合いの凄腕プログラマーを誘って入社させた: 優れた人材を得るには多大なコストがかかるもので、そのプロセスを人脈の力で省略できれば会社にとって非常に価値があります。
bold;">電話を率先して取る(小さい会社限定?) : 下らないことのように思うかもしれませんが、他の人達が業務に集中できる環境を作るという意味で、これも立派な業務効率改善です。

これ以外にも、いくらでも価値を生み出す方法はあると思いますし、何が価値になるかは仕事内容によっても、会社によっても違うと思います。

あなたの価値はおいくら?

一般的に、社員ひとりを1ヶ月養うのに月給の2倍ぐらいの経費がかかっているそうです。

ものすごく乱暴な言い方をしてしまえば、月給が額面30万円であれば、60万円ぐらいが「会社が1ヶ月であなたに提供してもらうことを期待している価値」ということになります。

そこで、「自分はその金額に値する価値を提供できているのか?」という視点から見ると、自分の働きがある程度定量的に評価できます。

とはいえ、新入社員である内は「今、価値があること」ではなく、「将来価値ある人材になるべくがんばること」が価値なので、あんまり考えすぎず、自分のやれることをやるのが一番でしょう。

ただ、意識しておくことは重要です。黙って8時間席に座っていればどこかから給料が湧いて出てくるわけではないのです。

まとめ

とまあ、なんか夢もキボーもありゃしないことを書き連ねてきましたが、いかがでしたでしょうか?

2行にまとめると

  1. 仕事においては「仕事の目的」にフォーカスを合わせて行動する。
  2. 自分がどういう価値を生み出せているかを意識する。

といったところです。


僕が最初の会社に居た頃は今書いたようなことは全然さっぱり全く意識できていませんでした。

Javaの会社でいきなりpythonを導入しようとして大反対にあい、ふてくされながらServletでWebアプリを書く毎日でした。

今思い返せばばかな奴だったなーと思います。実際結構怒られました。


プログラミングに限らず、趣味だったり好きなことだったりを仕事にすると、少なからずこういうジレンマにぶつかることがあります。

めんどくせー事考えずにやりたいようにやりたい と思ったことだって何度もあります。

トンチンカンな事を言ってくるお客さんだっていますし、予算や期間が足りなくてやりたかったことが出来ないまま終わることだってあります。

そういう障害を知恵と技術でうまいことかわし、可能なかぎりいいモノを、出来れば自分も他人も満足するような最高のモノを作り上げて価値につなげるのがエンジニアという仕事だと思います。

僕はこの仕事のそーいうところが、とても楽しいと感じます。

みなさんも、自分が楽しいと思えることで価値を生み出せるようなエンジニアになれるように頑張ってください。

僕も頑張ります。

本など

本を紹介するのがテンプレらしいので紹介しておきます。

人を動かす 新装版

人を動かす 新装版

id:nullpobug も紹介していましたが、僕からもおすすめします。

チームや会社やお客さんを動かすのはとても難しいもので、どんなに正しかったり良いことだったりしても、闇雲に主張を繰り返すだけではまず失敗します。

タイトルまんまですが、人を動かしたいと思ったときに、読んでみてください。

次回予告

次はid:kuenishiさんです。

案件ふりかえり

とある案件が終わった。相変わらずきっつい納期だったうえに、全メンバー片手間の情況でよくやれたなと自画自賛していいと思う。

ふりかえりをツイートしたら清水川大明神先生様に「それブログで」って言われたので、すこし整理してみた。

テスト

テストを書く習慣が付いたのはつい数ヶ月前のことなのだが、この案件ではテストが非常に役立った。

もともとFlashゲームのバックエンドAPIサーバーを作る仕事だったのでサーバー側のテストがしやすいというのもあったが、初期からテストのしやすさを意識して書いた。

マイルストーン期日が押していても1機能に対して最低ひとつ、想定通りの値で想定通りの結果が返ることを確認するテストを書いた。

それだけでも下らないバグは十分に防げた。

目標設定

テストの数が50を越えた頃から、100テストを目標にしていた。

カバレッジとかは一切計算していないし、100という数字にも何の根拠もない。単純にわかりやすいのと、3桁に対する憧れみたいなものがあったというだけ。

強いて言うなら「全くテストしてない機能」をゼロにするように心がけた。上でも書いたけど。

数が多くなってくるとただテストが走りきる様を見ているだけでも楽しくって、自然とテストを走らせる回数も増え、バグによる手戻りの回数はかなり少なく抑えられた。

ついでにテストを走らせるコマンドの名前を案件のキャッチコピーにして、パスを通してどこでも走らせられるようにしておいた。

中盤以降は殆ど儀式的にそのコマンドを打ち、テスト数が増えていることを確認してにやにやしながら、バグを潰してpushという流れができていた。

たのしみをつくる

楽しいというのは結構重要で、今回は楽しみの源泉であるテストを増やすために機能実装をしていた感すらある。

もちろん受託仕事の目的はモノを作って納品してそれがうまく動くことであってテスト100個ではないのだが、モチベーション維持にとても役立ったのは確かだし、結果的に品質も開発スピードも向上させることができた。

いくら仕事とはいえ面白くなさそうに作ってちゃ良い物ができるはずもない。

そういう意味で、個人的orチーム的な範囲で、楽しくやるためのエンターテインメント的要素をひとつぐらい設定してみるというのはありだと思った。

結果

結局、12000行ぐらいのロジックに対して160項目のテストを書くことができました。

すくないっちゃすくないかもしれないけど、進歩はしている。

次もこの調子でいきたいね。

5/50

案件ふりかえりそのに

またも清水川大明神先生様に「それブログで」って言われたので、もうすこしまとめてみた。まだまだである。

お客さんとプログラマー

プログラマー(SE?)の仕事はお客さんが持ってるもやもやとしたアイデアを最終的に動くプログラムというカタチに変換してあげることだ。

しかしプログラムは思ったとおりには動かず、書いたとおりに動くものなので、まず仕様に落としてやらないといけない。

で、これが大変辛い。開発の苦労の半分ぐらいは、いわゆるクソ仕様と呼ばれるものから発生する。

だれが決める?

弊社だとこれを大体実装者と同じ人間がやるので、実装負荷と仕様策定の負荷が重なってたいへん辛い。

さらに他にメンバーが居ると厄介で、実装負荷を持ってもらう代わりに仕様を余す所なく伝えるという作業まで発生するのでもう泣きそうになる。

ここで伝え漏れ、認識の齟齬があるとコレジャナイロボを作るハメになり、さらに苦行が続く。

仕様変更はぶちょう窓口へ

で今回の案件の話に戻ると、そこの負荷をほぼすべてぶちょうが一人で持ってくれたので非常に楽ができた。

仕様をまとめて文書化し、お客さんと調整しながら、実装者の僕らにtracチケットのカタチにまで落として割り振り、お客さんに出す前の確認までやってくれたので、あとはめいめいが落ちているチケットをちぎっては投げちぎっては投げすることに専念するだけでよかった。

もちろんおかしい仕様はあったが、それを報告して

「これはこうでないと矛盾してるので、こんなんでどうすか」「りょうかい、仕様書直して先方に伝えます」

みたいなやりとりをするだけで済むので、実装者としては大変有り難かった。

お客さんのアイデアではなく、実装すべき仕様とだけ対話していればいいのでものすごく楽。

マルチプレイヤー or 分業化

うちは要件ヒアリングから運用保守まで一人でやるようなことが多いので、わりとヒーヒーいうことが多い。

今回は完全分業だったが、十二分にスピードと(納期の短さに対する)品質は確保できていたと思う。

少なくとも、3人でお客さんとやりとりし、3人であれこれ言いながら仕様を0から決めて実装した場合よりは良い結果になったはずだ。

一つの役割に徹する

役割分担をきっちり決めて、与えられた単一のロールに全力を注ぐというやりかたはとても効率的。

もっと言うなら、どのロールもやれる人達が集まって、お互い動きやすいように配慮しつつ、各人がより得意とするロールを受け持つというのが最も効率が出せる戦い方ではなかろうか。


できるなら、こんな働き方をずっと続けたいものだ。

6/50

デフォルトマネージャという地雷

djangoのモデルデータはマネージャというオブジェクトを介して取得します。

独自定義のマネージャを使うことでデフォルトとは違う挙動をさせることができて便利ですが、地雷もありますよという話。

http://docs.djangoproject.com/en/1.2/topics/db/managers/#custom-managers

マネージャのカスタマイズ

class MyManager(models.Manager):
    def get_query_set(self):
        return super(MyManager, self).get_query_set().filter(is_deleted=False)
        
    def with_user(self, user):
        return self.filter(user=user)
        
class MyModel(models.Model):
    is_deleted = models.BooleanField(u"削除フラグ", default=False)
    user = models.ForeignKey(User, verbose_name=u"ユーザー")

    published = MyManager()

こんなふうに定義すると

>>> MyModel.published.all()
[is_deleted=Falseのモデル全部]

>>> MyModel.published.with_user(user)
[is_deleted=False, user=userのモデル]

>>> MyModel.objects.all()
[全てのMyModel]

と、publishedマネージャを使うだけで自動的に削除フラグの立っているものを除外するフィルタを掛けられて、大変便利なわけです。

地雷

モデルにはデフォルトマネージャというものがあり、明示的に指定しない場合はそのクラス定義の中で一番最初に見つかったマネージャオブジェクトをデフォルトマネージャとして使うようになっています。

なので、MyModelの場合はpublishedに使われているMyManagerがデフォルトマネージャとして使われることになります。

爆発

  1. ☠adminの挙動が狂う☠

adminではdefault_managerを使ってオブジェクトの一覧を取得します。

なので、is_deletedフラグを落とすとMyModelの管理画面上から消滅します。

つまり、表示状態に戻せません。

  1. ☠逆引き時のマネージャ☠

上記の定義だと

>>> user.mymodel_set.all()

としてリレーションを逆に辿ることができるわけですが、このmymodel_setはRelatedManagerというオブジェクトで、デフォルトマネージャをベースに動的に作られます。

つまり、暗黙のうちにis_deleted=Falseというフィルタがここにも掛かっているということになります。

取れて欲しいオブジェクトが取れなかったり、取れないはずのオブジェクトが取れたりして大変不愉快な挙動を示します。

回避

デフォルトマネージャは極力素のmodels.Managerオブジェクトにしておくとよいです。

class MyModel(models.Model):
    is_deleted = models.BooleanField(u"削除フラグ", default=False)
    user = models.ForeignKey(User, verbose_name=u"ユーザー")

    objects = models.Manager()
    published = MyManager()

こうすれば1番目がManagerになるので地雷は回避できます。もしくは、default_manager = models.Manager()というのでもいいです。

むしろ

managerを複数生やす=自分で地雷を埋めているようなものなので、よっぽど必然性が無い限りはobjects一つにしておくのが無難です。

publishedで実現したかった機能(is_deleted=Trueのオブジェクトを簡単に外す)を実現したければ、例えばget_query_setでやってることを普通のメソッドに移すなどの方法があります。

class MyManager(models.Manager):
    def be(self):
        return self.filter(is_deleted=False)
        
    def with_user(self, user):
        return self.be().filter(user=user)

>>> MyModel.objects.be().filter(...)
[is_deleted=False+その他の条件で絞りこまれたオブジェクト]

おわり

3/50

早くもペースがやばいです。