nokogiriとMechanizeでスクレイピングその1
趣味の関係でmixiをたまに使うのですが、(毎日見てないので)特定のコミュの書き込みがあったらメール飛んでくるようにしたいなと思いチャレンジ。
とりあえずログインして中の情報をなんとなくとってくるとこまで。
文字コードをちゃんと設定してないせいか、\nがたくさん出てる。
参考
スクレイピングのためのNokogiri利用メモ - それはそれ。これはこれ。
エンジニアの給料
エンジニアに最も高給を支払っている企業は意外にも・・・? | THE NEW CLASSIC
うーん、高いですね。
どの企業も世界的企業なので、単純に日本の企業と比較はできないかもしれませんが、やっぱりすごく高いと感じちゃいますね。
日本の企業で高そうなイメージだとDeNAとGreeでしょうか。
DeNA、GREE、サイバーエージェントの平均年収を比較してみた | CyberTimes [シバタイムス]
仕事の報酬は仕事
こんな記事がTLに流れてきました。
スタバはなぜ値下げやテレビCMをしない?高いブランド力構築の戦略を元CEOに聞く
http://zasshi.news.yahoo.co.jp/article?a=20131012-00010000-bjournal-bus_all&1381526511
この記事の中で気になったのが、「仕事の報酬は仕事」という言葉。
調べてみたら、昔からある言葉みたいですね。(誰が最初か、というのはよくわかりませんでしたが)
良い言葉だとは思いますが、一歩間違うと社畜一直線にもなってしまうので、使い方には注意が必要だなーと感じました。
http://www.gexeed.co.jp/column/cl018.html
http://bizmakoto.jp/makoto/articles/1106/08/news012.html
http://www.esofken.com/rensai/1011.html
仕事の報酬でより良い仕事を得て、その循環の先に何があるのか。
だから、給料は大事じゃない(低くても良い)って論調になると、違うんじゃないかな、と思います。どっちが大事って事ではなく、どっちも大事。
私は仕事が好きですが、仕事以外にも好きな事がいっぱいあるので、それを実現するためにはお金と時間が必要です。
結局、多くの人にとって人生の大部分を占める仕事において、何を求めるか、という哲学的な話になってくるのでしょうか。。。
InnoDBとREPEATABLE READとSELECT FOR UPDATEと楽観ロックその2
前回の話に排他(行ロック)を絡めてみる。
Versionカラムを使った楽観ロックをしてみます。
■ストーリー
1.セッション1 トランザクション開始
2.セッション2 トランザクション開始
3.セッション1 行情報取得→versionカラムを使って楽観ロックをした更新→commit or rollback
4.セッション2 行情報取得→versionカラムを使って楽観ロックをした更新→commit or rollback
楽観ロックなので、1行も更新できなかった場合はrollbackする想定です。
長いので1,2は省略しちゃいます。
READ COMMITTED
セッション1mysql> select * from Version; +----+------+---------+ | id | text | version | +----+------+---------+ | 1 | init | 1 | +----+------+---------+ 1 row in set (0.00 sec) mysql> update Version set text = 'updatedFromSession1' , version = version + 1 where id = 1 and version = 1; Query OK, 1 row affected (0.00 sec) Rows matched: 1 Changed: 1 Warnings: 0 mysql> commit; Query OK, 0 rows affected (0.00 sec)
セッション2
mysql> update Version set text = 'updatedFromSession2' where id = 1 and version = 2; Query OK, 1 row affected (0.00 sec) Rows matched: 1 Changed: 1 Warnings: 0 mysql> commit; Query OK, 0 rows affected (0.00 sec)
通ってしまいます。
REPEATABLE READ
セッション1mysql> select * from Version; +----+------+---------+ | id | text | version | +----+------+---------+ | 1 | init | 1 | +----+------+---------+ 1 row in set (0.00 sec) mysql> update Version set text = 'updatedFromSession1' , version = version + 1 where id = 1 and version = 1; Query OK, 1 row affected (0.00 sec) Rows matched: 1 Changed: 1 Warnings: 0 mysql> commit; Query OK, 0 rows affected (0.00 sec)
セッション2
mysql> select * from Version; +----+---------------------+---------+ | id | text | version | +----+---------------------+---------+ | 1 | updatedFromSession1 | 2 | +----+---------------------+---------+ 1 row in set (0.00 sec) mysql> update Version set text = 'updatedFromSession2' where id = 1 and version = 2; Query OK, 1 row affected (0.00 sec) Rows matched: 1 Changed: 1 Warnings: 0 mysql> commit; Query OK, 0 rows affected (0.00 sec)
こちらも通ってしまいます。
ここでストーリーを少し変えて、
■ストーリー
1.セッション1 トランザクション開始、tempテーブルselect
2.セッション2 トランザクション開始、tempテーブルselect
3.セッション1 行情報取得→versionカラムを使って楽観ロックをした更新→commit or rollback
4.セッション2 行情報取得→versionカラムを使って楽観ロックをした更新→commit or rollback
tempテーブルのselectを入れただけです。(for updateは無し)
READ COMMITTED
セッション1
mysql> select * from Version; +----+------+---------+ | id | text | version | +----+------+---------+ | 1 | init | 1 | +----+------+---------+ 1 row in set (0.01 sec) mysql> update Version set text = 'updatedFromSession1' , version = version + 1 where id = 1 and version = 1; Query OK, 1 row affected (0.01 sec) Rows matched: 1 Changed: 1 Warnings: 0 mysql> commit; Query OK, 0 rows affected (0.00 sec)
セッション2
mysql> select * from Version; +----+---------------------+---------+ | id | text | version | +----+---------------------+---------+ | 1 | updatedFromSession1 | 2 | +----+---------------------+---------+ 1 row in set (0.00 sec) mysql> update Version set text = 'updatedFromSession2' where id = 1 and version = 2; Query OK, 1 row affected (0.00 sec) Rows matched: 1 Changed: 1 Warnings: 0 mysql> commit; Query OK, 0 rows affected (0.00 sec)
変更前と同じ。
REPEATABLE READ
セッション1
mysql> select * from Version; +----+------+---------+ | id | text | version | +----+------+---------+ | 1 | init | 1 | +----+------+---------+ 1 row in set (0.00 sec) mysql> update Version set text = 'updatedFromSession1' , version = version + 1 where id = 1 and version = 1; Query OK, 1 row affected (0.00 sec) Rows matched: 1 Changed: 1 Warnings: 0 mysql> commit; Query OK, 0 rows affected (0.00 sec)
セッション2
mysql> select * from Version; +----+------+---------+ | id | text | version | +----+------+---------+ | 1 | init | 1 | +----+------+---------+ 1 row in set (0.00 sec) mysql> update Version set text = 'updatedFromSession2' where id = 1 and version = 1; Query OK, 0 rows affected (0.00 sec) Rows matched: 0 Changed: 0 Warnings: 0 mysql> rollback; Query OK, 0 rows affected (0.00 sec)
なんと結果が変わります。
REPEATABLE READの場合、最初のselectのタイミングで取得するデータのスナップショットが決まるらしいです。
http://dev.mysql.com/doc/refman/5.1/ja/innodb-consistent-read.html
今回だと、2でtempをselectした時点でセッション2中でselectの結果として返ってくる値が全テーブルで確定するようです。
というわけで、1,2の処理にinsertやらが入っていても、REPEATABLE READなら排他がばっちり決まります。
またストーリーを少し変えてみます。
■ストーリー
1.セッション1 トランザクション開始、tempテーブルselect
2.セッション2 トランザクション開始、tempテーブルselect
3.セッション1 行情報取得(for update)
4.セッション2 行情報取得(for update)※トランザクション1のコミット待ち
5.セッション1 versionカラムを使って楽観ロックをした更新→commit or rollback
6.セッション2 versionカラムを使って楽観ロックをした更新→commit or rollback
楽観ロックがかかってるのに、for updateで悲観ロックをかけたとします。
で、コミットのタイミングを変えました。
READ COMMITTED
セッション1mysql> select * from Version where id = 1 for update; +----+------+---------+ | id | text | version | +----+------+---------+ | 1 | init | 1 | +----+------+---------+ 1 row in set (0.00 sec)
セッション2
mysql> select * from Version where id = 1 for update;
ロック開放待ち。
セッション1
mysql> update Version set text = 'updatedFromSession1' , version = version + 1 where id = 1 and version = 1; Query OK, 1 row affected (0.00 sec) Rows matched: 1 Changed: 1 Warnings: 0 mysql> commit; Query OK, 0 rows affected (0.00 sec)
セッション2
+----+---------------------+---------+ | id | text | version | +----+---------------------+---------+ | 1 | updatedFromSession1 | 2 | +----+---------------------+---------+ 1 row in set (8.33 sec) mysql> update Version set text = 'updatedFromSession2' where id = 1 and version = 2; Query OK, 1 row affected (0.00 sec) Rows matched: 1 Changed: 1 Warnings: 0 mysql> commit; Query OK, 0 rows affected (0.00 sec)
REPEATABLE READ
セッション1mysql> select * from Version where id = 1 for update; +----+------+---------+ | id | text | version | +----+------+---------+ | 1 | init | 1 | +----+------+---------+ 1 row in set (0.00 sec)
セッション2
mysql> select * from Version where id = 1 for update;
ロック開放待ち。
セッション1
mysql> update Version set text = 'updatedFromSession1' , version = version + 1 where id = 1 and version = 1; Query OK, 1 row affected (0.01 sec) Rows matched: 1 Changed: 1 Warnings: 0 mysql> commit; Query OK, 0 rows affected (0.00 sec)
セッション2
+----+---------------------+---------+ | id | text | version | +----+---------------------+---------+ | 1 | updatedFromSession1 | 2 | +----+---------------------+---------+ 1 row in set (7.38 sec) mysql> update Version set text = 'updatedFromSession2' where id = 1 and version = 2; Query OK, 1 row affected (0.01 sec) Rows matched: 1 Changed: 1 Warnings: 0 mysql> commit; Query OK, 0 rows affected (0.00 sec)
なんと、通ってしまいました。
REPEATABLE READでトランザクション開始後に1度selectしていても、select for update をかけると他トランザクションの影響を受けてしまうようです。
まとめ
REPEATABLE READの場合、READ COMMITTEDに比べて楽観ロックがシビアに効くこと場合がある。ただし、select for updateで悲観ロックするとREAD COMMITTEDの場合と同じになる。
既存処理で、楽観ロックだけどシビアに排他が効いてる処理を、
何気なく悲観ロック追加すると挙動が変わる場合があるので注意する。
InnoDBのトランザクションは、ネクストキーロックとかもあって、
ハマるポイントが多いですね。。
InnoDBとREPEATABLE READとSELECT FOR UPDATEと楽観ロックその1
現場でちょっとはまった話。
InnoDBのトランザクション分離レベルhttp://dev.mysql.com/doc/refman/5.1/ja/innodb-transaction-isolation.html
InnoDBはトランザクション分離レベルが選べますが、
デフォルトは「REPEATABLE READ」です。
Oracleは「READ COMMITTED」に近いとの事。(どこが違うんだろう。。)
じゃあこの2つどう違うかというと、
READ COMMITTED
セッション1mysql> begin; Query OK, 0 rows affected (0.00 sec) mysql> select * from Version; +----+------+---------+ | id | text | version | +----+------+---------+ | 1 | init | 1 | +----+------+---------+ 1 row in set (0.00 sec)
セッション2
mysql> begin; Query OK, 0 rows affected (0.00 sec) mysql> select * from Version; +----+------+---------+ | id | text | version | +----+------+---------+ | 1 | init | 1 | +----+------+---------+ 1 row in set (0.00 sec)
セッション1
mysql> update Version set text = 'updated' , version = version + 1 where id = 1; Query OK, 1 row affected (0.00 sec) Rows matched: 1 Changed: 1 Warnings: 0 mysql> select * from Version; +----+---------+---------+ | id | text | version | +----+---------+---------+ | 1 | updated | 2 | +----+---------+---------+ 1 row in set (0.00 sec)
セッション2
mysql> select * from Version; +----+------+---------+ | id | text | version | +----+------+---------+ | 1 | init | 1 | +----+------+---------+ 1 row in set (0.00 sec)
セッション1
mysql> commit; Query OK, 0 rows affected (0.00 sec) mysql> select * from Version; +----+---------+---------+ | id | text | version | +----+---------+---------+ | 1 | updated | 2 | +----+---------+---------+ 1 row in set (0.00 sec)
セッション2
mysql> select * from Version; +----+---------+---------+ | id | text | version | +----+---------+---------+ | 1 | updated | 2 | +----+---------+---------+ 1 row in set (0.00 sec) mysql> commit; Query OK, 0 rows affected (0.00 sec) mysql> select * from Version; +----+---------+---------+ | id | text | version | +----+---------+---------+ | 1 | updated | 2 | +----+---------+---------+ 1 row in set (0.00 sec)
セッション1がコミットした段階で、セッション2にも更新が反映されました。
REPEATABLE READ
セッション1mysql> begin; Query OK, 0 rows affected (0.00 sec) mysql> select * from Version; +----+------+---------+ | id | text | version | +----+------+---------+ | 1 | init | 1 | +----+------+---------+ 1 row in set (0.00 sec)
セッション2
mysql> begin; Query OK, 0 rows affected (0.00 sec) mysql> select * from Version; +----+------+---------+ | id | text | version | +----+------+---------+ | 1 | init | 1 | +----+------+---------+ 1 row in set (0.00 sec)
セッション1
mysql> update Version set text = 'updated' , version = version + 1 where id = 1; Query OK, 1 row affected (0.00 sec) Rows matched: 1 Changed: 1 Warnings: 0 mysql> select * from Version; +----+---------+---------+ | id | text | version | +----+---------+---------+ | 1 | updated | 2 | +----+---------+---------+ 1 row in set (0.00 sec)
セッション2
mysql> select * from Version; +----+------+---------+ | id | text | version | +----+------+---------+ | 1 | init | 1 | +----+------+---------+ 1 row in set (0.00 sec)
セッション1
mysql> commit; Query OK, 0 rows affected (0.00 sec) mysql> select * from Version; +----+---------+---------+ | id | text | version | +----+---------+---------+ | 1 | updated | 2 | +----+---------+---------+ 1 row in set (0.00 sec)
セッション2
mysql> select * from Version; +----+------+---------+ | id | text | version | +----+------+---------+ | 1 | init | 1 | +----+------+---------+ 1 row in set (0.00 sec) mysql> commit; Query OK, 0 rows affected (0.00 sec) mysql> select * from Version; +----+---------+---------+ | id | text | version | +----+---------+---------+ | 1 | updated | 2 | +----+---------+---------+ 1 row in set (0.00 sec)
commitしないとセッション1の更新が反映されない!
という感じで、セッション1が更新した内容をセッション2に反映されるのはセッション2がコミットした後(ロールバックでもOK)になります。
自分はOracle脳になっていたので、最初意味がわかりませんでした。。。
長いので次回に続く。
第69回 PHP勉強会に参加してきた #phpstudy
初参加してきました。
http://atnd.org/events/40476
PHP歴半年ほど(そもそも仕事でばりばりプログラム書くようになって半年ですが。。。)の身でちょっと心配でしたが、アットホームな感じで楽しい会でした。
ビールの乾杯から始まるってのが良いですね。
今回は8周年記念という事でした。
他の言語ユーザーからはPHPェ。。。と言われがちなPHPですが、
集まってる方達はガチな感じですごかったです。
とりあえず、発表(LT以外)の感想だけでも。
Vagrant + Chef で作るこれからの開発環境 @yando
全然知りませんでしたが良さそうですね。ローカルと本番で違う環境(MySQLのバージョンとか。。。)で動かしちゃってるんで、実際に検討してみようかと。php-gd2で画像を弄る話(仮) @yoyapp
gdのコアな話でした。palletとtrue colorの話からして頂いたので、非常にわかりやすかったです。
また行こう。
select count(distinct user_id)的な
最近Railsをちょいちょいさわる機会があります。
よくある、
select count(distinct user_id) from hoge_users;
みたいなSQLですが、ActiveRecordだと
Hoge_users.count('user_id', :distinct => true)
でいける。簡単でいいですね。
複数行レコードを横持ちに変える
GROUP_CONCATが最高に便利。サブクエリとかいらない。
http://d.hatena.ne.jp/kkz_tech/20100803/1280802260
http://blog.asial.co.jp/209
転職してました
随分日が空いてしまいましたが、昨年の9月末から恵比寿でゲーム作ってる会社で働いています。もう4ヶ月位ですね。
所謂ソシャゲーを作っています。最初は若干抵抗もありましたが、作ってみるとなかなか楽しいです。ソシャゲーはすごい儲かるみたいなイメージがありましたが、それだけ苦労もしてるなーという印象です。
言語的にはPHPとjs(とHTML)なので、転職前にぼんやり考えてたのとは違いますが、アジャイルな感じでばりばり仕様考えて即コーディング!で仕事できていて、余計なストレスは少ないです。
仕事にも慣れてきてある程度コントロールできるようになってきたので、ブログ書いたり、勉強会参加したりしたいなと思っています。
とりあえず近況報告まで。
Akasaka.scala 41 #akskscala
Scala勉強会第83回 in 秋葉原
初参戦。
いきなりですが、少ししゃべってきました。
http://www.slideshare.net/moyashidaisuke/20120718-scala
Slideshare初めて使いましたが、OpenOfficeのファイルだとフォントとか段落とか色々おかしいですね。
後、うまく埋め込みができないです。また仕様変更??
以下、メモ
- Scala Schoolには@seratchさんの意訳があり、あわせて読むと便利
- polymorphismにはランクという考え方が有り、Scalaは1までしかサポートしてない。Haskellだと2もサポート?
- 2.10では「SIP-11 - String Interpolation and formatting」という機能が追加される。結構便利そう
- @kmizuさんの記事見つけた
- ジェネリクスの型情報はコンパイル時に消えるはずが、実は色んな方法で取得できるらしい。
なぜアジャイルをやってみたいのか考える
退職しましたで、「アジャイルやりたいなぁ」と書いたのですが、もう少し掘り下げてみます。
経験した現場の何がダメだった?
- 成果
- 予算・期間:オーバー
- 品質:低い
- 使いにくい
- バグ多い
いわゆる失敗プロジェクトですね。
経験した現場がなぜダメだった?
- 工程
- 無駄とおもえる作業が多い
- 大量のドキュメント
- 生産性が低いフレームワーク、開発の規約
- 明らかになっているリスクへの無対策により発生するコスト
- 単体テストまで完了させたのにリリースしない機能(予算超過のため)
- コミュニケーションエラー
- 仕様について言った言わない
- ここからは契約外なのでできません(追加費用が発生します)
- 追加要求のみしてくるユーザー、1次受け
- 無駄とおもえる作業が多い
- 体制、組織風土
- 改善提案を受け入れられない
- PDCA・カイゼン活動をしない
- リスクコントロールしない
- 名ばかりの管理者(1次受けの人)
- 形だけのレビュー
- 技術力不足
- 明らかなテスト不足による障害
- 保守性・拡張性に乏しいコード
集約するとこんな感じかと思います。
- 開発工程・契約
- 顧客・開発のプロジェクト管理能力不足
- 開発の技術力不足
じゃあどうしたらいい?
そこでアジャイルという可能性に出会いました。
プロセスやツールよりも個人と対話を、
包括的なドキュメントよりも動くソフトウェアを、
契約交渉よりも顧客との協調を、
計画に従うことよりも変化への対応を、価値とする。
そう、これだよ!
決められているやり方に縛られて契約上にしか価値の無いドキュメントを作るのをやめて開発作業にもっと力を注いで、「契約だからできない」ではなくてどうやったらお互いにWinWinになれるか考えて、実際には必ず発生する変化を前提に取り組めば、プロジェクトが成功する確率はもっと高くなると思いました。
さらに
ビジネス側の人と開発者は、プロジェクトを通して日々一緒に働かなければなりません。
プロジェクトの成功には顧客側の積極的な関わりが必須。
意欲に満ちた人々を集めてプロジェクトを構成します。環境と支援を与え仕事が無事終わるまで彼らを信頼します。
ヤル気ない人、定時内に出勤している事が仕事だと思っている人はプロジェクトにとってマイナス。いない方がいいです。
技術的卓越性と優れた設計に対する不断の注意が機敏さを高めます。
技術者は技術に対する努力をし続けるべき。
最良のアーキテクチャ・要求・設計は、自己組織的なチームから生み出されます。
チームがもっと効率を高めることができるかを定期的に振り返り、それに基づいて自分たちのやり方を最適に調整します。
組織は人の寄せ集めでは無いです。人員を代替可能なものとして見積もるやり方はもうやりたくないです。
というわけで、考え方にとても共感できました。
この考え方に共感できる人が集まっているプロジェクトなら、とても良い仕事ができるんじゃないか、と。
で、どうする?
SI業界でもアジャイル化の動きが出ていますが、結果が出るのはもう少し先かと思います。
となると、Webサービス系の企業にチャンスがありそうです。
でも、今までやってきたBtoBのSIを、ちゃんと成功させてみたいなぁ、という気持ちもあります。むむむ。
参考
アジャイルサムライ 読書会 埼玉道場(第4回)
超ゴージャスだった第1回に続き、久々に参戦。2回目。
以下、めも。
第3章 みんなをバスに乗せる
- 基本的にインセプションデッキの内容や目的は、PMBOKのプロジェクト憲章と同じ。でも継続的にメンテをする。
- 完璧に作れなくても(というか無理)良いので、できる範囲で作成すればおk。ぼやっとしてる部分はぼやっとしている事を明確になっていればおk
- プロジェクトが立ち上がる前(キックオフの前)に作成するのが効果的?
- プロジェクト憲章と同じ。
第4章 全体像を捉える
- 「司令官」って誰の事? => プロジェクトの目標・目的を司令官に例えてるだけなので、具体的にきまっているわけではない。
- パッケージデザインを作る必要性は?エレベーターピッチと何が違う?
- パッケージデザインはエンドユーザーから見たメリット。後、作るのが楽しいのでチームの一体感が出るのでは?
第5章 具現化させる
- 荒ぶる四天王でスコープだけが変更可能としてあるけど、ウォーターフォールでは時間と予算を伸ばすことの方が多かったため、いまいち実感できない。
- スコープの変更とは機能を削るだけでなく、機能の簡素化(画面の共通化とか)も含まれる。
- ウォーターフォールの場合、時間と予算には予めバッファを積んである事が常なので、変更しやすいのでは?
- ステークホルダーとご近所さんの違いは?
- 第5章の最終判断の下りでの「ステークホルダー」は利害関係者ではなく出資者の意味では?
- ご近所さんにはステークホルダー(利害関係者)も含むと捉えて良いのでは
その他
インセプションデッキとか、エレベーターピッチとかウォーターフォールでは使わない単語を良い感じに翻訳しているので、「アジャイル」という単語を出さずに進めたい場合に良さそうです。